0

私は現在、タスク並列ライブラリを使用して結果が生成される速度を向上させる小さなシミュレーションユーティリティを開発しています。シミュレーション自体は、CPUを集中的に使用する長いジョブであり、基本的に、さまざまな変数を使用してシミュレーションを実行する数千の小さなジョブで構成されています。

ただし、各タスクで使用されるリソースは、すべてが完了するまで解放されないため、十分な変数が使用されている場合は、メモリリークが発生し、メモリ不足の例外が発生します。各タスクの最後にGCを強制するとリソースが解放されますが、実行するにはすべてのスレッドを中断する必要があるため、シングルスレッドのパフォーマンスに近い結果になると理解しています。

このような長時間の操作中にリソースを解放するにはどうすればよいですか?

この文脈での「リソース」とは、doubleの配列を指します...それらの多くです。

public List<AnalysisTask> Questions; //Each variable combination is added as a Q

//Create a task for each simulation
Task<SimulationResults>[] tasks = new Task<SimulationResults>[Questions.Count]; 
foreach(var q in Questions)
{
    AnalysisTask temp = q
    tasks[taskCount] = Task.Factory.StartNew((t) =>
             {
                var result = EvaluateRules(temp);
                if(reults.Value > Leader[0].Value)
                    Leader[0] = result;
                else
                {
                    result.Dispose();
                    //This releases resources but interrupts threads
                    //GC.Collect(2, GCCollectionMode.Forced); 
                    return null;
                }
                return result;

             }
}

//Completion task
Task.Factory.ContinueWhenAll(tasks, (ant) =>
       {
          DoSomethingWithAnswer(Leader[0]);
       }

おそらく私はタスクを設定する際に間違ったアプローチを取りましたか?アドバイスや指示に感謝します:)

4

3 に答える 3

1

現在の実装にはいくつかの問題があります。1つは、と交換するとLeader[0]、前のリーダーの参照が失われ、破棄されないことです。これがメモリリークの原因である可能性があります。2つ目は、比較と割り当てLeader[0]がアトミックに行われないことです。次の一連のイベントが発生する可能性があります。スレッド1Leader[0]はaと比較してtrueになりresult.Value、スレッド2はaと比較しLeader[0]てtrueになりresult.Value、スレッド2はに書き込みLeader[0]、スレッド1はに書き込みますLeader[0]。その結果Leader[0]、最大値が2のときの値は1になります。

したがって、参照を適切に破棄すれば、ガベージコレクションを強制する必要がない場合があります。Leader以下のコードは、前のへの参照を変更および保存するときにロックを解除することにより、これらの問題を修正しますLeader[0]。次に、未使用の結果または前のリーダーのいずれかが破棄されます。おそらくEvaluateRules時間がかかるので、ロックの競合はあまりないはずです。

tasks[taskCount] = Task.Factory.StartNew(() =>
     {
        var result = EvaluateRules(temp);

        var toBeDisposed = result;
        lock(Leader) // should be locking on a private object
        {
           if (result.Value > Leader[0].Value)
           {
             toBeDisposed = Leader[0];
             Leader[0] = result;
           }
        }

        toBeDisposed.Dispose();       

     });

resultまた、各タスクから戻る必要がありますか?Leader[0]継続タスクのみが必要なようです。戻るresultことにより、タスク自体がgcされるまでgcされない参照を保存します。

于 2012-06-23T22:07:36.420 に答える
0

ガベージコレクションは、プロセス全体を停止するわけではありません。詳細については、こちらをご覧ください。

GCを呼び出す必要がある場合(またはプロセスが停止する場合)、およびGCが実際にパフォーマンスを低下させる場合(常にGCを実行する可能性は低い、シミュレーションをいつでも複数のプロセスに分割できます(プロセスを使用しないでください)。もちろん、スレッドごとですが、すべてのXスレッドは1つのプロセスに属することができます)。

ただし、メモリ管理で何か問題が発生している可能性があることは認めざるを得ませんが、より多くの情報を提供する必要があります。

于 2012-06-23T20:56:23.813 に答える
0

配列が一定のサイズであるか、最大サイズを定義できるか、サイズ範囲のセットを定義できる場合は、起動時にこれらの配列のプールを作成するか、実行中にサイズの配列のリストのプールを構築できます。 。そうすれば、アレイの割り当てを解除する必要はありません。後で再利用するためにアレイを再プールするだけです。BlockingCollection[sizeRange]キューの配列はプールとして機能します。

于 2012-06-23T20:56:48.007 に答える