2

System.Drawing クラスを使用して画像のリストを処理しています。通常の foreach ループ内で画像を処理する場合はすべて問題ありませんが、画像をループしている場合 (画像とは、使い捨ての System.Drawing.Image インスタンスを意味するのではなく、画像のソース (URL) を意味します) Parallel.ForEach を使用して実行しますメモリ不足です。プロセスがどんどん大きくなります (> 1GB)。すべてのリソースを解放するように注意しましたが、グラフィック バッファーが解放されていないようです。これは、非並列 foreach(...) に切り替えるだけで確認できます。プロセスは約 60 MB のままです。

このような問題に遭遇しましたか?

        // memory "leak". process grows beyound 1GB to infinity
        Parallel.ForEach(urls, url =>
        {
            ImageResizer.DownloadAndResizeImage(url);
        });


        // no memory "leak"
        foreach (string url in urls)
        {
            ImageResizer.DownloadAndResizeImage(url);
        }
4

2 に答える 2

3

Parallel.Invokeは、一度に複数の画像を処理しようとしているため、処理中により多くのメモリを消費すると予想されます。Parallel.Invokeは、すべてのタスクが完了するのを待ってから戻ります。「メモリ不足」エラーが発生したと言うので、決して戻らないと思います。したがって、メモリリークが発生しているかどうかを知る方法はありません。

Parallel.Invokeを使用して2つの画像だけを処理してみて、プロセスが終了したときにメモリが既知の開始点に戻るかどうかを確認してください。その場合、メモリリークは発生しません。システムが一度に処理できる以上の処理を試みているだけです。

その場合は、代わりにParallel.ForEachを使用してみてください。代わりに、MaxDegreeOfParallelismを使用するスレッド数に制限を設けてください。

私が最初に試すこと(4つのコアがある場合):

Parallel.ForEach( 
    urls, 
    new ParallelOptions { MaxDegreeOfParallelism = 4 }, 
    url => { ImageResizer.DownloadAndResizeImage(url); } 
); 

編集:

質問はParallel.InvokeからParallel.ForEachに変更され、コードが追加されているようです:)が、Parallel.ForEachはすべてのタスクが完了するまで待機するため、私の答えはそれほど変わりません。

DownloadAndResizeImage()メソッドが原因である可能性が高く、Parallelではないと思います。リクエストを非同期で正しく処理するには、低レベルのネットワークAPIを使用してかなりの量の開発が必要です。MicrosoftのWebClientまたはHttpWebRequestオブジェクトを使用すると、マルチスレッドを介して非同期で作成できる要求の数を制限する既知のボトルネックがあります。私は最近同じことを試みて、自分でソケットレイヤーを書くことになったので、これを知っています。イッピー!

したがって、発生する可能性が高いのは、各要求が行われ、一度に2つだけが処理され、他の要求は順番を待ってキューに積み上げられることです。しかし、待機している間、すべてのオブジェクトが初期化されているため、メモリが増大します。最終的に(十分なメモリがある場合)、実行に時間がかかりすぎた失敗した要求からタイムアウトが発生することがわかります。

何百ものリクエストをスクリーンスクレイプするように設計されたフリーウェアアプリケーションがいくつかあります。低レベルのコードをいくつか入手して、アプリに実装することをお勧めします。ここから、ソケットについて学び始めるのに適した場所です。

http://msdn.microsoft.com/en-us/magazine/cc300760.aspx

于 2012-06-16T12:45:57.557 に答える
1

Parallel.ForEach は、CPU コアよりも多くのスレッドを開始する傾向があります。50 個のスレッドまたは実行中のスレッドがあるため、メモリ リークが発生しているように見える場合があります。

処理中にデバッガーを一時停止し、実行中のスレッドが多すぎるかどうかを確認する必要があります。

于 2012-06-16T12:55:35.513 に答える