我正在尝试从2-3小时解决此问题,但无法修复它。我正在尝试三个部分三个线程下载文件。问题是当一个部件完成时,其他线程停止下载。
Example: let's say i want to download 300kb
part1->t1->100kb
part2->t2->100kb //if this thread get completed then other two become unresponsive.
part3->t3->100kb
我正在使用的代码(已修改且更短,但解决了我的问题)
//inside a function
WebResponse wresp = wreq.GetResponse();
long e1 = wresp.ContentLength / 3;
long e2 = 2*e1;
long e3 = wresp.ContentLength;
wreq.Abort();
wresp.Close();
wreq = null;
wresp = null;
byte[] buff1 = new byte[1500];
byte[] buff2 = new byte[1500];
byte[] buff3 = new byte[1500];
HttpWebRequest hr1 = (HttpWebRequest)WebRequest.Create(textBox1.Text);
hr1.AddRange(0, e1-1);
WebResponse wresp1 = hr1.GetResponse();
HttpWebRequest hr2 = (HttpWebRequest)WebRequest.Create(textBox1.Text);
hr2.AddRange(e1,e2-1);
WebResponse wresp2 = hr2.GetResponse();
HttpWebRequest hr3 = hr1;//(HttpWebRequest)WebRequest.Create(textBox1.Text);
hr3.AddRange(e2,e3);
WebResponse wresp3 = hr3.GetResponse();
Stream response1 = wresp1.GetResponseStream();
Stream response2 = wresp2.GetResponseStream();
Stream response3 = wresp3.GetResponseStream();
Stream f1, f2, f3;
f1 = File.Create("Part1");
f2 = File.Create("Part2");
f3 = File.Create("Part3");
int bytesRead=0, bytesProcessed=0;
long total1=e1, total2=e2-e1, total3=e3-e2;
int x1=0, x2=0, x3=0;
Thread t1 = new Thread(() =>download(hr1, wresp1, buff1,response1,f1,bytesRead, bytesProcessed,total1,x1));
t1.Name = "1";
Thread t2 = new Thread(() => download(hr2, wresp2, buff2, response2, f2, bytesRead, bytesProcessed,total2,x2));
t2.Name = "2";
Thread t3 = new Thread(() => download(hr3, wresp3, buff3, response3, f3, bytesRead, bytesProcessed, total3,x3));
t3.Name = "3";
t1.Start();
t2.Start();
t3.Start();
}
}
}
private download(HttpWebRequest hr2, WebResponse wresp2, byte[] buff, Stream response, Stream f,int bytesRead,long bytesProcessed,long total,int x)
{
do
{
lock (lockerObj)
{
bytesRead = response.Read(buff, 0, buff.Length);
bytesProcessed += bytesRead;
f.Write(buff, 0, bytesRead);
x = Convert.ToInt32(Thread.CurrentThread.Name) - 1;
pb[x].Invoke((Action)delegate
{
pb[x].Value = Convert.ToInt32(bytesProcessed * 100 / total);
});
if (bytesProcessed >= total)
{
Thread.CurrentThread.Abort();
break;
}
lb[x].Invoke((Action)delegate
{
lb[x].Text = "Downloaded " + Convert.ToDouble((bytesProcessed * 100 / total)).ToString() + "%";
label4.Text = "thread" + (x + 1);
});
}
} while (bytesProcessed<=total && bytesRead>=0 );
}
static readonly Object lockerObj=new Object(); //at global level
应用程序ui保持响应,从调试中我意识到每个线程同时退出。所以问题是为什么其他线程没有完成他们的部分。
答案 0 :(得分:4)
您在download
方法的循环结束时遇到此情况:
while (bytesProcessed<=0 && bytesRead>0 );
那是你的问题。第一次循环时,bytesProcessed
会增加读取的字节数,这会使其大于0,这会导致条件为false并且循环退出。
你永远不会在循环中进行多次迭代。
顺便说一句,并非每个回复都有一个有效的ContentLength
。网页通常不提供Content-Length标头,在这种情况下,ContentLength
属性将为-1。即使页面确实提供了Content-Length标头,也不能保证它是正确的。因此,在一般情况下,您不能保证您已收到全部内容。
正如Servy在他的评论中指出的那样,在多个线程之间拆分下载不太可能提高性能,事实很可能导致下载速度变慢。如果某个站点看到您发出三个并发请求并决定对您进行速率限制或阻止,则尤其如此。一般情况下,使用单个HttpWebRequest
进行正常下载会更好。它更可靠,它简化了代码,并且可能比您编码的过于复杂的多线程版本表现更好。
答案 1 :(得分:-3)
我同意@Kyle Pittman。最有可能是BytesRead和BytesProcessed变量是导致问题的原因。