C# 下载100个文件后,线程似乎卡住了
我刚刚编写了一个下载管理器来并行下载多个文件。但是我对这个脚本有一个问题,我找不到答案。经过大量的文件(100个就可以了)。有时候一根线就是不能完成它的工作。它不会触发超时,也没有我放置的异常或控制台日志。当我检查需要下载所有文件的文件夹时,我看到那里有一个不完整的文件,应用程序正在使用它(我知道这一点,因为在关闭应用程序之前我无法删除该文件)。我希望有人能在我的剧本中看到这个问题C# 下载100个文件后,线程似乎卡住了,c#,multithreading,http,C#,Multithreading,Http,我刚刚编写了一个下载管理器来并行下载多个文件。但是我对这个脚本有一个问题,我找不到答案。经过大量的文件(100个就可以了)。有时候一根线就是不能完成它的工作。它不会触发超时,也没有我放置的异常或控制台日志。当我检查需要下载所有文件的文件夹时,我看到那里有一个不完整的文件,应用程序正在使用它(我知道这一点,因为在关闭应用程序之前我无法删除该文件)。我希望有人能在我的剧本中看到这个问题 //Download complete delegate public delegate void Downloa
//Download complete delegate
public delegate void DownloadCompleteHandler(DownloadableObject source, DownloadCompletedEventArgs e);
//Download complete event args
public class DownloadCompletedEventArgs : EventArgs
{
private string EventInfo;
public DownloadCompletedEventArgs(string text)
{
EventInfo = text;
}
public string GetInfo()
{
return EventInfo;
}
}
class DownloadManager
{
//Downloadcomplete Handler
public event DownloadCompleteHandler DownloadComplete;
//The amount of downloads that can run in parallel
public int parallelDownloads = 1;
//All the downloads in a list
public List<DownloadableObject> downloads = new List<DownloadableObject>();
public DownloadManager(int parallelDownloads = 1)
{
this.parallelDownloads = parallelDownloads;
}
//This adds a download to the list.
public void addDownload(string url, string saveLocation)
{
DownloadableObject dl = new DownloadableObject() { url = url, saveLocation = saveLocation };
downloads.Add(dl);
}
//This starts the parallel downloader
public void startParallelDownloads()
{
for(int i = 0; i < parallelDownloads; i++)
{
startDownload();
}
}
//This starts a single download Async
private void startDownload()
{
//Check if the downloads list contains anything
if(downloads.Any())
{
//Get the first download from the list and remove it so it doesn't get downloaded again.
DownloadableObject currentDl = downloads[0];
downloads.RemoveAt(0);
//Setup a webrequest.
HttpWebRequest webRequest = (HttpWebRequest)WebRequest.Create(currentDl.url);
webRequest.Method = "GET";
webRequest.Timeout = 4000;
currentDl.webRequest = webRequest;
IAsyncResult result = webRequest.BeginGetResponse(new AsyncCallback(downloadResponse), currentDl);
//This handles the timeout response
ThreadPool.RegisterWaitForSingleObject(result.AsyncWaitHandle, new WaitOrTimerCallback(timeoutCallback), currentDl, currentDl.webRequest.Timeout, true);
} else
{
//Called when a Thread is done downloading. This should be called when the download list is empty
Console.WriteLine("THREAD DONE!");
}
}
//This is the callback when a timeout occurs
private void timeoutCallback(object state, bool timedOut)
{
if(timedOut)
{
//Get the timedout request
HttpWebRequest request = ((DownloadableObject)state).webRequest;
if(request != null)
{
Console.WriteLine("Too Bad!");
//And abort it
request.Abort();
//Set the webrequest in the downloadable object to null and add it to the download list again so it will be downloaded again
((DownloadableObject)state).webRequest = null;
downloads.Add(((DownloadableObject)state));
//Refire the thread.
startDownload();
}
}
}
private void downloadResponse(IAsyncResult asyncResult)
{
int received = 0;
//Get the current download from the asyncResult.
DownloadableObject currentDl = (DownloadableObject)asyncResult.AsyncState;
try
{
using (HttpWebResponse webResponse = (HttpWebResponse)currentDl.webRequest.EndGetResponse(asyncResult))
{
byte[] buffer = new byte[1024];
//Creates a file in the correct location.
FileStream fileStream = File.OpenWrite(currentDl.saveLocation);
using (Stream input = webResponse.GetResponseStream())
{
//Write data to the buffer.
int size = input.Read(buffer, 0, buffer.Length);
while (size > 0)
{
fileStream.Write(buffer, 0, size);
received += size;
size = input.Read(buffer, 0, buffer.Length);
}
}
//Write data to the file and close it.
fileStream.Flush();
fileStream.Close();
//Call the download complete event
DownloadComplete(currentDl, new DownloadCompletedEventArgs("Download completed"));
//refire the Thread again.
startDownload();
}
}
catch (WebException e)
{
}
}
}
//A downloadable object.
public class DownloadableObject
{
//Url to file to download
public string url { get; set; }
//Location where to save the file
public string saveLocation { get; set; }
//The webrequest that is assigned to this download. This will be null when the download list is filled.
public HttpWebRequest webRequest { get; set; }
}
//下载完整的委托
公共委托void DownloadCompleteHandler(DownloadableObject源,DownloadCompletedEventArgs e);
//下载完整的事件参数
公共类下载CompletedEventArgs:EventArgs
{
私有字符串EventInfo;
公共下载CompletedEventArgs(字符串文本)
{
事件信息=文本;
}
公共字符串GetInfo()
{
返回事件信息;
}
}
类下载管理器
{
//下载完整处理程序
公共事件下载完成处理程序下载完成;
//可并行运行的下载量
公共int=1;
//列表中的所有下载
公共列表下载=新列表();
公共下载管理器(int parallelDownloads=1)
{
this.parallelldownloads=parallelldownloads;
}
//这会将下载添加到列表中。
public void addDownload(字符串url、字符串saveLocation)
{
DownloadableObject dl=新的DownloadableObject(){url=url,saveLocation=saveLocation};
下载.添加(dl);
}
//这将启动并行下载程序
public void startParallelDownloads()
{
for(int i=0;i0)
{
写入(缓冲区,0,大小);
接收+=大小;
size=input.Read(buffer,0,buffer.Length);
}
}
//将数据写入文件并关闭它。
Flush();
fileStream.Close();
//调用下载完成事件
下载完成(currentDl,新的下载完成事件参数(“下载完成”);
//把线再重新装一遍。
startDownload();
}
}
捕获(WebE例外)
{
}
}
}
//可下载的对象。
公共类可下载对象
{
//要下载的文件的Url
公共字符串url{get;set;}
//保存文件的位置
公共字符串保存位置{get;set;}
//分配给此下载的webrequest。填写下载列表时,此值将为空。
公共HttpWebRequest webRequest{get;set;}
}
Q:您是否连接了调试器并查看了“挂起”行的堆栈跟踪?问:是否只有一个线程挂起(其他线程是否完成其工作?)“几个线程”。。。还是整个程序挂起?它是随机的。我刚刚测试了2200个文件,有2个线程挂起。如何检查线程是在哪一行上