c#下载器:我应该使用线程、后台工作者还是线程池?

本文关键字:线程 工作者 后台 我应该 下载 | 更新日期: 2023-09-27 18:04:21

我正在用c#编写一个下载程序,并停在以下问题:我应该使用什么样的方法来并行化我的下载和更新我的GUI?

在我的第一次尝试中,我使用了4个线程,并在每个线程完成时启动另一个线程:主要问题是我的cpu在每个新线程启动时都达到100%。

谷歌周围,我发现后台工作者和ThreadPool的存在:声明我想更新我的GUI与我正在下载的每个链接的进度,什么是最好的解决方案?

1)创建4个不同的BackgroundWorker,附加到每个ProgressChanged事件一个委托到一个函数在我的GUI更新进度?

2)使用ThreadPool并设置最大和最小线程数为相同的值?

如果我选择#2,当队列中没有更多的线程时,它会停止4个工作线程吗?它会暂停它们吗?由于我必须下载不同的链接列表(每个链接20个),并在一个完成时从一个移动到另一个,ThreadPool是否在每个列表之间启动和停止线程?

如果我想改变工作线程的数量,并决定使用ThreadPool,从10个线程改为6个,它是否抛出和异常,并停止4个随机线程?

这是唯一让我头疼的部分。

c#下载器:我应该使用线程、后台工作者还是线程池?

我建议使用WebClient.DownloadFileAsync。您可以同时进行多次下载,每次下载过程中触发DownloadProgressChanged事件,完成后触发DownloadFileCompleted事件。

你可以通过使用带有信号量的队列来控制并发性,如果你使用的是。net 4.0,可以使用BlockingCollection。例如:

// 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

我认为你应该考虑使用任务并行库,它是。net 4中的新特性,专为解决这类问题而设计的

拥有100%的cpu负载与下载无关(因为您的网络实际上总是瓶颈)。我想说你必须检查你的逻辑如何等待下载完成。

你能发布一些你多次启动的线程代码的代码吗?

通过创建4个不同的后台工作者,您将创建不再干扰您的GUI的单独线程。后台工作人员很容易实现,据我所知,他们会做你需要他们做的事情。

我个人会这样做,只是允许其他人不开始,直到前一个完成。(或者可能只有一个,并允许它一次以正确的顺序执行一个方法。)

供参考- Backgroundworker