【发布时间】:2015-11-23 06:56:44
【问题描述】:
我对线程很陌生,所以我的实现无疑是非常初级的。
我正在尝试生成 8 个或更多线程,每个线程使用 FTPWebRequest 下载文件,以并行运行。
所有线程似乎都已生成并完成它们的工作,但任何时候只有两个线程在工作。他们似乎在排队。
谁能建议我可能做错了什么以及如何解决这个问题?
private void btnDownload_Click(object sender, EventArgs e)
{
int itemCount = lBoxList.Items.Count;
string[] listOfFilesToDownload = new string[itemCount];
for (int i = 0; i < itemCount; i++)
{
listOfFilesToDownload[i] = (string)lBoxList.Items[i];
}
FtpParallelDownload("ftp://ftp.somedomain.com/sub/sub2/sub3/", (int)this.nudNumberOfThreads.Value, listOfFilesToDownload, tBoxDownloadPath.Text);
}
public static void FtpParallelDownload(string serverUri, int maxNumberOfThreads, string[] listOfFilesToDownload, string downloadPath)
{
int progressPercent = 0;
// Validate number of threads requested
if (!(maxNumberOfThreads >= 1))
{
ArgumentException e = new ArgumentException();
throw e;
}
// Calc number of files based on array length
int numberOfFiles = listOfFilesToDownload.Length;
// Don't spawn more threads than files
if (maxNumberOfThreads > numberOfFiles)
{
maxNumberOfThreads = numberOfFiles;
}
// Thread spawning
List<Thread> threadPool = new List<Thread>();
int runningThreadCount = 0;
for (int i = 0; i < numberOfFiles; i++)
{
if (runningThreadCount < maxNumberOfThreads)
{
Thread workerThread = new Thread(() => FtpDownloadFile(serverUri, listOfFilesToDownload[i], downloadPath));
threadPool.Add(workerThread);
workerThread.Start();
runningThreadCount++;
}
else
{
i--;
}
List<Thread> removeThreadList = new List<Thread>();
foreach (Thread t in threadPool)
{
if (!t.IsAlive)
{
removeThreadList.Add(t);
}
}
foreach (Thread t in removeThreadList)
{
threadPool.Remove(t);
runningThreadCount--;
}
removeThreadList.Clear();
}
MessageBox.Show("DOWNLOADS COMPLETE!");
}
private static void FtpDownloadFile(string serverUri, string fileName, string downloadPath)
{
try
{
FtpWebRequest request = (FtpWebRequest)FtpWebRequest.Create(new Uri(serverUri + fileName));
request.Method = WebRequestMethods.Ftp.DownloadFile;
request.Credentials = new NetworkCredential("anonymous", "noreply@mydomain.com");
FtpWebResponse response = (FtpWebResponse)request.GetResponse();
Stream responseStream = response.GetResponseStream();
FileStream writeStream = new FileStream(downloadPath + "/" + fileName, FileMode.Create);
int Length = 4096;
Byte[] buffer = new Byte[Length];
int bytesRead = responseStream.Read(buffer, 0, Length);
while (bytesRead > 0)
{
writeStream.Write(buffer, 0, bytesRead);
bytesRead = responseStream.Read(buffer, 0, Length);
Thread.Sleep(10);
}
writeStream.Close();
response.Close();
responseStream.Close();
}
catch (WebException wEx)
{
MessageBox.Show(wEx.Message, "Download Error");
}
catch (Exception ex)
{
MessageBox.Show(ex.Message, "Download Error");
}
}
threadPool 是一个Thread<List>,我用它来监视活动线程的数量,以便在完成工作时产生更多线程。
【问题讨论】:
-
“threadPool 是一个线程,我用它来监视活动线程的数量,以便在完成工作时产生更多线程” - 由于令人难以置信的复杂性创建线程池;调度和动态优势,通常应该避免创建自己的实现。像你这样承认自己是“线程新手”的人绝对不应该制作自己的池机制。
-
如果没有更多细节,包括minimal reproducible example,就不可能确定发生了什么。但我会说你很有可能只是看到默认连接限制。参见例如HttpWebRequest takes a long time to send when there are a bunch at once from client 和 C# Manual Threading 进行可能的相关讨论。如果您在阅读完这些内容后仍然需要帮助,请改进问题。
-
“我正在尝试生成 8 个或更多线程,每个线程都通过 FTPWebRequest 下载文件”。你做错了什么是你试图使用多线程。您应该尝试使用异步 I/O。
-
这里用线程没什么问题,8个线程没什么。这应该基本上可以工作。彼得是对的。
-
Omg,
i--;是一种创建无限循环的创意方式:) 您的整个线程管理应该替换为 PLINQ 或Parallel.ForEach。删除所有这些。
标签: c# multithreading