繁体   English   中英

在C#中使用多线程时出现内存不足异常

[英]out of memory exception while using multithread in C#

我是线程技术的新手,并在此问题上停留在这里。 我有一个使用多线程的应用程序。 我有一个功能,可以在ftp服务器上上传数千个图像。 对于每个图像,我正在创建一个新线程。 该线程调用一个函数来连接ftp服务器,上传文件,如果上传成功,则返回布尔值。

我的问题是,由于我正在上传数千个图像,并且每个图像都在创建自己的线程,因此一段时间后,我会遇到内存不足异常并且应用程序冻结。

我的代码如下:

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。

您不能创建这么多线程。 一种替代方法是使用parrelle扩展名。

public void UploadFiles(string[] files)
{
    files.AsParallel().ForAll(fileName =>
    {
        if (UploadFile(fileName))
        {
            strLogText += "\r\n\tFile: " + fileName + " downloaded.";
        }
    });
}

尝试使用调用DownloadFileNow而不是UploadFile(String file)方法的Parallel.ForEach()替换UploadFiles(string [] files)中的foreach。

Parallel.Foreach将从您想要的线程池中提取线程,并简化您的代码。

 Parallel.ForEach(files, fileName =>
        DownloadFileNow(fileName);
        strLogText += "\r\n\tFile: " + fileName + " downloaded.";
 );

正如其他人指出的那样,您不应该创建那么多线程。 现在... Parallel.ForEach()将为您提供不错的语法糖,您应该走那条路!

只是想指出,您需要将线程池视为一个概念。 看到,并行运行大量线程没有意义。 对于每个这样的任务,都有一个最佳线程数,超过该线程数时,整个线程开销实际上将开始使您变慢。 或者,就您而言,用尽所有内存。

如果您将任务想象成一堆坐在办公桌(文件夹)上的照片,而线程又像是员工为您办事的线程,那么请一位员工从办公桌上取一张照片,将其放在信封中并带到办公室。邮局,对于每张照片,将永远保留下去。 因此,您雇用了另一名员工。 还有一个。 但是,一旦您达到一定数量的照片邮递员,它们就会开始互相影响。 他们在办公桌前排队。 他们在邮局门口排队。 对于负责办公用品的可怜的玛丽来说,整个信封的状况简直令人痛苦-他们也在她的面前排队! 因此,找出最佳员工人数(您可以运行测试或猜测一下),然后分配他们重复执行此任务,直到办公桌空了为止。

这是一个经常出现的主/从模式。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM