[英]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.