C#下载:我应该使用线程,BackgroundWorker的线程池还是?
我写在C#中下载并停在下面的问题:我应该用什么样的方法来并行我的下载和更新我的GUI
I'm writing a downloader in C# and stopped at the following problem: what kind of method should I use to parallelize my downloads and update my GUI?
在我第一次尝试,我用4个线程,并在他们每个人的完成,我开始另一个。主要的问题是我的CPU在每一个新的线程开始进入100%
In my first attempt, I used 4 Threads and at the completion of each of them I started another one: main problem was that my cpu goes 100% at each new thread start.
周围的Googling,我发现了BackgroundWorker的线程池和的存在?说明我想更新我与我下载的各个环节的进度GUI,什么是最好的解决方案。
Googling around, I found the existence of BackgroundWorker and ThreadPool: stating that I want to update my GUI with the progress of each link that I'm downloading, what is the best solution?
1)创建4个不同的BackgroundWorker的,注重每一个ProgressChanged事件委托给函数在我的GUI更新进度?
1) Creating 4 different BackgroundWorker, attaching to each ProgressChanged event a Delegate to a function in my GUI to update the progress?
2)使用线程池和设置线程最大和最小数为相同的值
2) Use ThreadPool and setting max and min number of threads to the same value?
如果我选择#2,当没有更多的线程队列中,它停止4个工作线程?是否暂停呢?因为我有下载链接不同的名单(他们每个人的20个链接),当一个完成了从一个移动到另一个,它的线程池开始,每个列表之间的停止线?
If I choose #2, when there are no more threads in the queue, does it stop the 4 working threads? Does it suspend them? Since I have to download different lists of links (20 links each of them) and move from one to another when one is completed, does the ThreadPool start and stop threads between each list?
如果我想改变带电作业的线程数,并决定使用线程池,从10个线程更改为6,是否抛出和异常并停止4个随机的主题?
If I want to change the number of working threads on live and decide to use ThreadPool, changing from 10 threads to 6, does it throw and exception and stop 4 random threads?
这是给我一个头痛的唯一部分。
我感谢你们每个人提前为你的答案。
This is the only part that is giving me an headache. I thank each of you in advance for your answers.
我会建议使用 WebClient.DownloadFileAsync
这一点。你可以有多个下载去,每次提高 DownloadProgressChanged
的事件,因为它去一起,和 DownloadFileCompleted
完成时。
I would suggest using WebClient.DownloadFileAsync
for this. You can have multiple downloads going, each raising the DownloadProgressChanged
event as it goes along, and DownloadFileCompleted
when done.
您可以通过使用一个队列,信号灯控制并发或者,如果你使用.NET 4.0,一个 BlockingCollection
。例如:
You can control the concurrency by using a queue with a semaphore or, if you're using .NET 4.0, a BlockingCollection
. For example:
// Information used in callbacks.
class DownloadArgs
{
public readonly string Url;
public readonly string Filename;
public readonly WebClient Client;
public DownloadArgs(string u, string f, WebClient c)
{
Url = u;
Filename = f;
Client = c;
}
}
const int MaxClients = 4;
// create a queue that allows the max items
BlockingCollection<WebClient> ClientQueue = new BlockingCollection<WebClient>(MaxClients);
// queue of urls to be downloaded (unbounded)
Queue<string> UrlQueue = new Queue<string>();
// create four WebClient instances and put them into the queue
for (int i = 0; i < MaxClients; ++i)
{
var cli = new WebClient();
cli.DownloadProgressChanged += DownloadProgressChanged;
cli.DownloadFileCompleted += DownloadFileCompleted;
ClientQueue.Add(cli);
}
// Fill the UrlQueue here
// Now go until the UrlQueue is empty
while (UrlQueue.Count > 0)
{
WebClient cli = ClientQueue.Take(); // blocks if there is no client available
string url = UrlQueue.Dequeue();
string fname = CreateOutputFilename(url); // or however you get the output file name
cli.DownloadFileAsync(new Uri(url), fname,
new DownloadArgs(url, fname, cli));
}
void DownloadProgressChanged(object sender, DownloadProgressChangedEventArgs e)
{
DownloadArgs args = (DownloadArgs)e.UserState;
// Do status updates for this download
}
void DownloadFileCompleted(object sender, AsyncCompletedEventArgs e)
{
DownloadArgs args = (DownloadArgs)e.UserState;
// do whatever UI updates
// now put this client back into the queue
ClientQueue.Add(args.Client);
}
有没有需要显式管理线程或去TPL。
There's no need for explicitly managing threads or going to the TPL.