4

Task Parallel Library の Task.WaitAll(..) について頭を悩ませようとしています。

次のコードを使用してテストを実行し、2 つのタスクをシミュレートしようとしています。待機する時間. 指定された時間は 5 秒です. 私が使用しているコードは次のとおりです:

Task<int>[] tasks = new Task<int>[]
{
    Task.Factory.StartNew<int>(()=>
        {
            Thread.Sleep(10000);
            return 1;
        }),
    Task.Factory.StartNew<int>(()=>
        {
            Thread.Sleep(3000);
            return 2;
        })
};

TimeSpan timeSpan = new TimeSpan(0, 0, 5);
Task.WaitAll(tasks,timeSpan);

int[] results = new int[tasks.Length];
for(int i = 0; i < tasks.Length;i++)
{
    Console.WriteLine(tasks[i].Result);
}

timeSpan に関しては、timeSpan 変数の代わりに 5000 を直接渡そうとしましたが、うまくいきません。次の出力が得られます。

1
2

他のスレッドが予想される待機時間よりも長く実行されているため、次の出力のみが得られると予想されます。

1

私はこれを誤解していますか、それともこのテストを間違っていますか?

4

3 に答える 3

11

Task.Delayは通常、代わりに使用したいものですが(つまり、スリープ中にスレッドを無駄にすることはありません)、問題は実際にはそれに関連していません。

ここで起こっていることは、結果を印刷するときに、各タスクのResultプロパティにアクセスしているということです。これにより、タスクの完了がブロックされるため、WaitAllで5秒間待機し、10秒のタスクの結果を出力するときにさらに5秒間待機します。

表明された意図に基づいて、結果にアクセスする前にタスクのステータスを確認する必要があります。これは、タスクをブロックすることではなく、すでに終了している場合にのみ印刷することを目的としているためです。

int[] results = new int[tasks.Length];
for (int i = 0; i < tasks.Length; i++)
{
    if (tasks[i].IsCompleted)
    {
        Console.WriteLine(tasks[i].Result);
    }
}

ところで、いくつかの簡単な時間チェックを追加するだけで、「結果のブロック」が元のコードで起こっていることを示すことができます(たとえば、このようなストップウォッチを使用して)

Task<int>[] tasks = new Task<int>[]
{
    Task.Factory.StartNew<int>(()=>
        {
            Thread.Sleep(10000);
            return 1;
        }),
    Task.Factory.StartNew<int>(()=>
        {
            Thread.Sleep(3000);
            return 2;
        })
};

TimeSpan timeSpan = new TimeSpan(0, 0, 5);
var stopwatch = Stopwatch.StartNew();
Task.WaitAll(tasks, timeSpan);
Console.WriteLine("WaitAll took {0} seconds", stopwatch.Elapsed.TotalSeconds);

int[] results = new int[tasks.Length];
for (int i = 0; i < tasks.Length; i++)
{
    stopwatch = Stopwatch.StartNew();
    Console.WriteLine(tasks[i].Result);
    Console.WriteLine("Printing result took {0} seconds", stopwatch.Elapsed.TotalSeconds);
}

これにより、次のコンソール出力が生成されます。

WaitAll took 4.9996961 seconds
1
Printing result took 5.0050012 seconds
2
Printing result took 0.0004338 seconds
于 2012-09-07T15:39:19.930 に答える
3

タスクで Thread.Sleep を使用しないでください。スケジューラは、Taskタスクごとに 1 つのスレッドを保証するものではなく、スリープは他のタスクに影響を与える可能性があります (「タスクが Thread.Sleep を無視する」を参照)。代わりにTask.Delay()を使用してください。

于 2012-09-07T15:17:43.557 に答える
0

期間をに変換してみてください

TimeSpan span = new TimeSpan(0, 0, 0, 10, 0);
//TimeSpan(Days, hours, minutes, seconds, milliseconds);
于 2012-09-07T15:21:29.573 に答える