1

私はスレッド化が初めてで、この問題で立ち往生しています。マルチスレッドを使用しているアプリケーションがあります。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 個を超えないように、作成されるスレッドの数を制限する方法を教えてください。

4

3 に答える 3

1

他の人が指摘しているように、それほど多くのスレッドを作成するべきではありません。さて...Parallel.ForEach()は素晴らしいシンタックス シュガーを提供するので、そのルートに進むべきです!

スレッドプールを概念として調べる必要があることを指摘したかっただけです。ほら、たくさんのスレッドを並行して実行するのは意味がありません。このようなタスクごとに最適なスレッド数があり、それを超えると、スレッドのオーバーヘッド全体が実際に遅くなり始めます。または、あなたの場合、すべてのメモリを使い果たします。

タスクを机の上に置かれた写真の山(フォルダー)と考え、スレッドを従業員が用事を済ませていると考えると、従業員の 1 人が机から写真を取り出し、封筒に入れて、オフィスに持ってきます。郵便局は、写真ごとに、永遠にかかります。だからあなたは別の従業員を雇います。そしてもう一つ。しかし、一定数のフォトスタンプポストガイに達すると、彼らはお互いの邪魔をし始めます. 彼らは机の前に並んでいます。彼らは郵便局の前に並んでいます。そして封筒全体の状況は、事務用品を担当する可哀想なメアリーにとっては苦痛でしかありません。彼女の前にも彼らが列を作っているのです。そのため、最適な人数の従業員を見つけ (テストを実行するか、少し推測するだけでもかまいません)、デスクが空になるまでそのタスクを繰り返すように割り当てます...

これはかなり頻繁に現れるマスター/スレーブ パターンです。

于 2013-07-25T15:47:03.080 に答える