簡體   English   中英

如何在有條件的情況下等待任務?

[英]How to wait tasks with conditions?

我有一些返回布爾值的任務。 我只想等到任何任務首先返回True時。 可能嗎 ?

我的第一個想法是使用CancellationTokenSource,但這不是一個好主意,因為當我調用Task.WaitAll方法時,它會引發異常。

第二種選擇是使用我在引用中傳遞的布爾值,如果為真,則直接返回。 它有效,但性能不高:

bool isFound = false;
Task<bool> t0 = Task.Factory.StartNew<bool>(() => Find(paramA, paramB, ref isFound));
Task<bool> t1 = Task.Factory.StartNew<bool>(() => Find(paramC, paramD, ref isFound));
Task<bool> t2 = Task.Factory.StartNew<bool>(() => Find(paramE, paramF, ref isFound));
Task<bool> t3 = Task.Factory.StartNew<bool>(() => Find(paramG, paramH, ref isFound));

Task.WaitAll(new Task[] { t0, t1, t2, t3, t4 });
return t0.Result | t1.Result | t2.Result | t3.Result | t4.Result;

並在方法中:

 private static bool Find(int[,] m1, int[,] m2, ref bool isFound)
 {
      if (isFound)
           return false;

      // Do work...
 }

編輯:

作為預先確定的答案,我現在使用TaskCompletionSource<bool>

TaskCompletionSource<bool> tcs = new TaskCompletionSource<bool>();
Task<bool> t0 = Task.Factory.StartNew<bool>(() => Find(paramA, paramB);
Task<bool> t1 = Task.Factory.StartNew<bool>(() => Find(paramC, paramD);
Task<bool> t2 = Task.Factory.StartNew<bool>(() => Find(paramE, paramF);
Task<bool> t3 = Task.Factory.StartNew<bool>(() => Find(paramG, paramH);

t0.ContinueWith(_ =>
{
    if (t0.Result)
        tcs.TrySetResult(t0.Result);
});

t1.ContinueWith(_ =>
{
    if (t1.Result)
        tcs.TrySetResult(t1.Result);
});

t2.ContinueWith(_ =>
{
    if (t2.Result)
        tcs.TrySetResult(t2.Result);
});

t3.ContinueWith(_ =>
{
    if (t3.Result)
        tcs.TrySetResult(t3.Result);
});

t4.ContinueWith(_ =>
{
    if (t4.Result)
        tcs.TrySetResult(t4.Result);
});

tcs.Task.Wait();
return tcs.Task.Result;

在這種情況下,當所有任務返回false時,什么也沒有發現,這是正常的。 但是我不知道如何使用WhenAll方法。 我試圖添加這個:

tcs.Task.Wait();
Task tr = Task.WhenAll(new Task[] { t0, t1, t2, t3, t4 });

if (tr.IsCompleted)
    return false;
else
    return tcs.Task.Result;

但這不起作用:(

一種選擇是創建TaskCompletionSource的任何類型的TaskCompletionSource (以標識結果,如果需要的話)。 然后,向每個任務添加延續,如果結果為true,則調用TaskCompletionSource.TrySetResult

然后只需等待TaskCompletionSource.Task 它避免了您必須重復調用Task.WaitAny ,檢查結果等情況。

棘手的一點是,當所有任務都返回false時,在.NET 4.5中,通過Task.WhenAll創建另一個任務,這將相當容易,那么您只需要等待{ success, all failed }中的第一個完成。

您需要WaitHandle.WaitAny 從一開始,您就設置了一個WaitHandle[] ,每個等待一個Task ,當任務成功執行(並按預期結果WaitHandle true )時,您將發出相應的WaitHandle信號。

您可以使用ManualResetEvent ,這幾乎會使您的isFound屬性變得多余,例如

private static ManualResetEvent found = new ManualResetEvent(false);
...

Task.Factory.StartNew<bool>(() => Find(paramA, paramB));     
Task.Factory.StartNew<bool>(() => Find(paramC, paramD));     
Task.Factory.StartNew<bool>(() => Find(paramE, paramF));     
Task.Factory.StartNew<bool>(() => Find(paramG, paramH));  

var result = found.WaitOne(TimeSpan.FromSeconds(10)); // wait with timeout of 10 secs

// do something with result

...
private static bool Find(int[,] m1, int[,] m2)          
{          
    if (found.WaitOne(0)) // check whether MSE has already been set
        return false;        

    // Do work...
    found.Set();
}

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM