我是线程新手并且坚持这个问题。我有一个应用程序,我正在使用多线程。我有一个功能,可以在ftp服务器上传上千张图片。对于每个图像,我正在创建一个新线程。该线程调用一个函数来连接ftp服务器,上传文件并在成功上传后返回布尔值。
我的问题是,因为我上传了数千张图片,每张图片都在创建自己的线程,过了一段时间我就会出现Out of Memory异常和应用冻结。
我的代码如下:
public Int16 UploadFiles(string[] files)
{
foreach (var fileName in files)
{
if (UploadFile(fileName))
{
strLogText += "\r\n\tFile: " + fileName + " downloaded.";
}
}
}
private bool UploadFile(string fileName)
{
var blnDownload = false;
var thread = new Thread(() => DownLoadFileNow(fileName, out blnDownload)) {IsBackground = true};
thread.Start();
return blnDownload;
}
private void DownLoadFileNow(string fileName, out bool blnDownload)
{
//Get file path and name on source ftp server
var srcFolder = GetSrcFolderName(fileName);
//Get Local Folder Name for downloaded files
var trgFolder = GetLocalFolder(fileName, "D");
var reqFtp =
(FtpWebRequest) WebRequest.Create(new Uri("ftp://" + _strSourceFtpurl + srcFolder + "/" + fileName));
reqFtp.Method = WebRequestMethods.Ftp.DownloadFile;
reqFtp.UseBinary = true;
reqFtp.Credentials = new NetworkCredential(_strSourceFtpUser, _strSourceFtpPassword);
var outputStream = new FileStream(trgFolder + "\\" + fileName, FileMode.Create);
try
{
var response = (FtpWebResponse) reqFtp.GetResponse();
var ftpStream = response.GetResponseStream();
const int bufferSize = 2048;
var buffer = new byte[bufferSize];
if (ftpStream != null)
{
int readCount = ftpStream.Read(buffer, 0, bufferSize);
while (readCount > 0)
{
outputStream.Write(buffer, 0, readCount);
readCount = ftpStream.Read(buffer, 0, bufferSize);
}
ftpStream.Close();
}
response.Close();
blnDownload = true;
}
catch (WebException ex)
{
_log.WriteLog("Error in Downloading File (" + fileName + "):\r\n\t" + ex.Message, "");
//Delete newly created file from local system
outputStream.Close();
if (File.Exists(trgFolder + "/" + fileName))
File.Delete(trgFolder + "/" + fileName);
}
catch (Exception ex)
{
_log.WriteLog("Error in Downloading File (" + fileName + "):\r\n\t" + ex.Message, "");
}
finally
{
outputStream.Close();
outputStream.Dispose();
}
blnDownload = false;
}
请帮助并让我知道如何限制正在创建的线程数,以便一次运行的线程不超过10-20个。
答案 0 :(得分:3)
您无法创建这么多线程。一种替代方法是使用并行扩展。
public void UploadFiles(string[] files)
{
files.AsParallel().ForAll(fileName =>
{
if (UploadFile(fileName))
{
strLogText += "\r\n\tFile: " + fileName + " downloaded.";
}
});
}
答案 1 :(得分:2)
尝试使用调用DownloadFileNow而不是UploadFile(String file)方法的Parallel.ForEach()替换UploadFiles(string []文件)中的foreach。
Parallel.Foreach将从线程池中提取线程,这是您想要的,并将简化您的代码。
Parallel.ForEach(files, fileName =>
DownloadFileNow(fileName);
strLogText += "\r\n\tFile: " + fileName + " downloaded.";
);
答案 2 :(得分:1)
正如其他人所指出的那样,你不应该创造那么多线程。现在...... Parallel.ForEach()
会给你很好的语法糖,你应该走这条路!
只是想指出,你需要查找线程池作为一个概念。看,没有多少线程并行运行是没有意义的。对于每个这样的任务,都有一个最佳线程数,超过该线程,整个线程开销实际上会开始减慢你的速度。或者,在你的情况下,用尽所有的记忆。
如果您将任务视为坐在桌子上的一堆照片(文件夹)以及作为员工为您跑腿的线程,那么让一名员工从桌面上取照片,将其放入信封并带上到邮局,对于每张照片,都将永远消失。所以你雇用了另一名员工。而另一个。但是,一旦你达到了一定数量的照片邮票后,他们就会开始相互影响。他们在桌子前排队。他们在邮局前排队。整个信封的情况对于负责办公用品的可怜玛丽来说是痛苦的 - 他们也在她面前排队!因此,找出最佳员工数量(您可以运行测试或只是猜测一下)并指定他们重复该任务,直到桌子为空......
这是一种经常出现的主/从模式。