I'm very new to threading, so my implementation is no doubt very rudimentary.
I'm attempting to spawn 8 or more threads that each download a file using FTPWebRequest
, to be run in parallel.
All the threads seem to be spawned and do their work, but only two ever do work at any one time. They seem to get queued.
Can anyone suggest what I may be doing wrong and how to solve the issue?
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
is a Thread<List>
that I am using to monitor the number of threads that are alive so as to spawn more when one is finished work.