Har*_*ips 1 c# multithreading timeout webclient exception
我正在开发一个使用定时Web客户端的项目.类结构是这样的.
Controller =>类Form1,SourceReader,ReportWriter,UrlFileReader,HTTPWorker,TimedWebClient的主要主管.
HTTPworker是在给出url时获取页面源的类.TimedWebClient是处理WebClient超时的类.这是代码.
class TimedWebClient : WebClient
{
int Timeout;
public TimedWebClient()
{
this.Timeout = 5000;
}
protected override WebRequest GetWebRequest(Uri address)
{
var objWebRequest = base.GetWebRequest(address);
objWebRequest.Timeout = this.Timeout;
return objWebRequest;
}
}
Run Code Online (Sandbox Code Playgroud)
在HTTPWorker中我有
TimedWebClient wclient = new TimedWebClient();
wclient.Proxy = WebRequest.GetSystemWebProxy();
wclient.Headers["Accept"] = "application/x-ms-application, image/jpeg, application/xaml+xml, image/gif, image/pjpeg, application/x-ms-xbap, application/x-shockwave-flash, application/vnd.ms-excel, application/vnd.ms-powerpoint, application/msword, */*";
wclient.Headers["User-Agent"] = "Mozilla/4.0 (compatible; MSIE 8.0; Windows NT 6.1; WOW64; Trident/4.0; SLCC2; .NET CLR 2.0.50727; .NET CLR 3.5.30729; .NET CLR 3.0.30729; Media Center PC 6.0; MDDC)";
string pagesource = wclient.DownloadData(requestUrl);
UTF8Encoding objUTF8 = new UTF8Encoding();
responseData = objUTF8.GetString(pagesource);
Run Code Online (Sandbox Code Playgroud)
我在那里处理了例外情况.在Form1中,我有一个背景控制器和一个urllist.
第一次实施:
首先,我一次取一个url并将其交给ONLY Controller对象进行处理.然后它工作正常.但由于它是连续的,因此列表太长时需要很长时间.
第二次实施:
然后在后台工作者的Do_Work中,我制作了七个控制器和七个线程.每个控制器都有唯一的HTTPWorker对象.但现在它抛出了"timedout"的异常.
下面是Form1.cs backgroundworker1_DoWork中的代码.
private void backgroundWorker1_DoWork(object sender, DoWorkEventArgs e)
{
bool done = false;
while (!backgroundWorker1.CancellationPending && !done)
{
int iterator = 1;
int tempiterator = iterator;
Controller[] cntrlrarray = new Controller[numofcontrollers];
Thread[] threadarray = new Thread[numofcontrollers];
int cntrlcntr = 0;
for ( cntrlcntr = 0; cntrlcntr < numofcontrollers; cntrlcntr++)
{
cntrlrarray[cntrlcntr] = new Controller();
}
cntrlcntr = 0;
for (iterator = 1; iterator <= this.urlList.Count; iterator++)
{
int assignedthreads = 0;
for (int threadcounter = 0; threadcounter < numofcontrollers; threadcounter++)
{
cntrlcntr = threadcounter;
threadarray[threadcounter] = new Thread(() => cntrlrarray[cntrlcntr].Process(iterator - 1));
threadarray[threadcounter].Name = this.urlList[iterator - 1];
threadarray[threadcounter].Start();
backgroundWorker1.ReportProgress(iterator);
assignedthreads++;
if (iterator == this.urlList.Count)
{
break;
}
else
{
iterator++;
}
}
for (int threadcounter = 0; threadcounter < assignedthreads; threadcounter++)
{
cntrlcntr = threadcounter;
threadarray[threadcounter].Join();
}
if (iterator == this.urlList.Count)
{
break;
}
else
{
iterator--;
}
}
done = true;
}
}
Run Code Online (Sandbox Code Playgroud)
这是什么原因和解决方案?因为过于冗长而适用.先感谢您.
天空......它充满了线程!但是说真的 - 不要使用这么多线程.这就是异步I/O的用途.如果您使用的是.NET 4.5,那么使用await/async非常容易,否则它是一些样板代码,但它仍然比这更好.
除此之外,默认情况下TCP连接的数量非常有限.即使有一次使用1000次下载(并且它可能不是,因为你正在共享带宽),你根本无法创建和删除TCP连接,因为打开TCP连接是有限的(除非你在服务器上,否则从5到20不等.你可以改变它,但通常更喜欢以不同的方式做事.看到这个条目.如果此应用程序不是单独运行(这可能不是,因为您在服务器Windows上不会出现这样的问题),这也可能是一个问题.例如,torrent客户端经常遇到半开连接限制(一个仍在等待初始TCP handskahe结束的连接).当然,这对你的申请来说是个腐朽的.
现在,即使您保持在此限制之下,在通信时也会使用固定数量的出站和入站端口.当您快速打开和关闭TCP连接时,这是一个问题,因为TCP使连接在后台保持活动大约4分钟(以确保没有错误的数据包到达端口,同时可以重复使用).这意味着如果您在此时间间隔内创建了足够的连接,那么您将"饿死"您的端口池,并且每个新的TCP连接都将被拒绝(因此您的浏览器将暂时停止工作等).
接下来,5秒的超时时间非常短.真.想象一下,完成握手需要一秒钟(这是一个~300ms的ping,这仍然在合理的互联网响应范围内).突然之间,你有一个新的连接,必须等待其他握手完成,可能需要几秒钟才能完成.而这仍然只是连接的启动.然后是DNS查找,以及HTTP服务器本身的响应...... 5秒是一个低超时.
简而言之,它不是多线程 - 它是你打开的大量(无用)连接.此外,对于单个Web上的URL,您应该查看Keep-Alive连接 - 它们可以重用已经打开的TCP连接,这可以显着缓解此问题.
现在,深入研究这一点.你正在开始并不必要地摧毁线程.相反,最好有一个URL队列和几个线程使用者,它们将从队列中获取输入.这样,只要有一些内容可以从队列中轮询,你就只有那些7(或任何数量)线程,这样可以节省大量系统资源(并提高性能).我在想你正在做的Thread.Join也可能与你的问题有关.即使你在背景工作者中运行这个东西,也许有可能在那里有一些奇怪的东西.
归档时间: |
|
查看次数: |
752 次 |
最近记录: |