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

本文关键字:内存不足 异常 多线程 | 更新日期: 2023-09-27 18:24:51

我是线程的新手,在这个问题上一直停留在这里。我有一个使用多线程的应用程序。我有一个在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个。

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

您不能创建这么多线程。一种替代方案是使用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[]文件)中的foreach。

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

 Parallel.ForEach(files, fileName =>
        DownloadFileNow(fileName);
        strLogText += "'r'n'tFile: " + fileName + " downloaded.";
 );
正如其他人所指出的,您不应该创建那么多线程。现在Parallel.ForEach()会给你很好的语法糖,你应该走这条路!

我只是想指出,您需要将线程池作为一个概念来查找。看,让大量线程并行运行是没有意义的。对于每一个这样的任务,都有一个最佳的线程数量,超过这个数量,整个线程开销实际上会开始降低速度。或者,在你的情况下,耗尽你所有的记忆。

如果你把任务想象成一堆坐在桌子上的照片(文件夹),把线程想象成员工为你跑腿,那么让一名员工从桌子上取一张照片,放在信封里,然后把它带到邮局,每张照片都需要很长时间。所以你雇佣了另一名员工。还有另一个。但是,一旦你接触到一定数量的照片邮票邮差,他们就会开始互相妨碍。他们在桌子前排队。他们在邮局前排队。对于负责办公用品的可怜的玛丽来说,整个信封的情况都很痛苦——他们也在她前面排队!因此,计算出员工的最佳数量(你可以进行测试或只是猜测一下),并让他们重复这项任务,直到桌子空了。。。

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