.net 在C语言中一次下载多个HTML#
我有一个需要下载的网址列表(>10k),如果我使用单线程应用程序下载非常耗时,那么多线程或多backgroundworker实例中的哪一个是更好的选择,为什么 如果您有GUI,那么建议使用.net 在C语言中一次下载多个HTML#,.net,multithreading,.net,Multithreading,我有一个需要下载的网址列表(>10k),如果我使用单线程应用程序下载非常耗时,那么多线程或多backgroundworker实例中的哪一个是更好的选择,为什么 如果您有GUI,那么建议使用BackgroundWorker一般来说,多线程处理使用多个线程(可能在服务器CPU的多个内核上)在应用程序等待代码返回时并行处理代码。在3.5版中引入了一个优秀的.Net多线程工具,称为。多线程最大的性能改进之一是在循环内的重复进程中使用多线程 背景工人不同。它们可能是多线程的,也可能不是多线程的。这里的要点
BackgroundWorker
一般来说,多线程处理使用多个线程(可能在服务器CPU的多个内核上)在应用程序等待代码返回时并行处理代码。在3.5版中引入了一个优秀的.Net多线程工具,称为。多线程最大的性能改进之一是在循环内的重复进程中使用多线程
背景工人不同。它们可能是多线程的,也可能不是多线程的。这里的要点是,应用程序代码不会暂停并等待后台进程完成。相反,主代码可以继续处理。当后台进程返回其结果时,会调用一个单独的方法。以下是来自以下方面的解释:
BackgroundWorker类允许您在服务器上运行操作
独立的、专用的线程。像下载这样耗时的操作
而数据库事务可能会导致用户界面(UI)看起来
就好像它在运行时停止了响应。当你
想要一个响应迅速的用户界面,您将面临与之相关的长时间延迟
通过这些操作,BackgroundWorker类提供了一个方便的
解决方案
多线程
或多个backgroundworker实例
在技术上解决了相同的问题。基本上,您可以使用线程池来使用这些用法,或者更好地使用Parallel.ForEach
。如果需要最大性能,请确保最小化线程和/或GUI之间的同步数据。我的方法是:
- 将链接放入队列中
- 启动N个线程,其中N个是可配置的
- 在每个线程中循环 取消链接队列 如果失败(队列为空),请退出线程 下载链接
- 在主线程上做一些UI工作-GUI或控制台上每隔几秒钟编写一次类似“运行,下载x/y文件”的内容
- 在主线程上,如果队列为空,请连接()其他线程
- 我遇到了完全相同的问题,并实施了节流策略和C#4.0任务工厂来解决它。在这种设计中,所有下载都发生在一个单独的线程中,该线程由一个信号量的静态实例限制。信号量限制在app.config中设置
public class Downloader
{
private static readonly Semaphore DownloadThrottle =
new Semaphore(Properties.Settings.Default.ThrottleCount,
Properties.Settings.Default.ThrottleCount);
public Task<bool> DownloadTaskThread { get; set; }
private string _url;
private string _localFileName;
public void Get(string url, string localFileName)
{
_url = url;
_localFileName = localFileName;
DownloadTaskThread = new Task<bool>(Worker);
DownloadTaskThread.Start();
}
private bool Worker()
{
try
{
DownloadThrottle.WaitOne();
using (WebClient wc = new WebClient())
{
wc.DownloadFile(_url, _localFileName);
return true;
}
}
catch (Exception ex)
{
Console.WriteLine(ex.Message);
}
finally
{
DownloadThrottle.Release();
}
return false;
}
}
公共类下载程序
{
私有静态只读信号量DownloadThrottle=
新信号量(Properties.Settings.Default.ThrottleCount,
Properties.Settings.Default.ThrottleCount);
公共任务下载任务线程{get;set;}
私有字符串url;
私有字符串\u localFileName;
public void Get(字符串url、字符串localFileName)
{
_url=url;
_localFileName=localFileName;
DownloadTaskThread=新任务(工作者);
下载TaskThread.Start();
}
私人布尔工人()
{
尝试
{
下载throttle.WaitOne();
使用(WebClient wc=new WebClient())
{
wc.DownloadFile(_url,_localFileName);
返回true;
}
}
捕获(例外情况除外)
{
控制台写入线(例如消息);
}
最后
{
下载throttle.Release();
}
返回false;
}
}
在这个类中,调用“Get”方法,它启动一个线程来执行工作。客户端类保留“DownloadTaskThread”实例的列表并轮询结果。当完成的任务数量达到可接受的水平时,会启动更多线程
Worker类中的节流阀和main类中的节流阀需要“调优”,以便在完成工作和应用程序的整体响应性之间取得平衡
使用信号量可以确保一次只执行一定数量的工作,从而保持UI的响应性
使用该类,您可以访问操作是如何完成的,即成功与否。任务实例是强类型的,因此您可以使用适合您的应用程序的任何类型的结果。在我的示例中,它返回bool。与以前的C#版本相比,这是一个很大的优势,后者只提供ThreadPool.QueueUserWorkItem(没有返回值)。通用类是有文档记录的您应该使用的方法在很大程度上取决于您下载这10000页的速度和频率 一般来说,单线程下载应用程序的平均速度约为每秒一页。您的结果将因您下载的站点而异。从yahoo.com上下载东西要比从有线调制解调器上托管的服务器上下载快得多。单线程下载应用程序的好处在于它非常容易编写。如果你只需要下载这些页面一次,那么就编写一个单线程应用程序,让它工作,然后吃一顿长长的午餐。您将在大约三小时内获得数据 如果你有一个四核机器,你可以做大约四页每秒。只需编写单线程应用程序,将URL列表分成四个相等的部分,启动应用程序的四个实例,并定期吃午餐。当你回来时,你会得到数据的 如果您将定期下载这些页面,那么您可以编写程序来维护URL的链接。旋转四个线程,每个线程基本上执行以下操作:
while (queue not empty)
{
dequeue url
download page
}
这将在与单线程下载程序的四个独立实例相同的时间内执行。事实上
while (url queue is not empty)
{
client = dequeue WebClient // this will block if all clients are currently busy
url = dequeue url
client.DownloadDataAsync(url)
}