2

我有一些返回布尔值的任务。我只想等到任何任务首先返回 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;

但它不起作用:(

4

3 回答 3

6

一种选择是创建TaskCompletionSource您想要的任何类型(如果需要,识别结果)。然后为每个任务添加一个延续,TaskCompletionSource.TrySetResult如果结果为真则调用。

然后就等着吧TaskCompletionSource.Task。它避免了你不得不Task.WaitAny反复打电话,检查结果等。

棘手的一点是,当所有任务都返回 falseTask.WhenAll{ success, all failed }......

于 2012-08-06T08:27:53.950 回答
3

你需要WaitHandle.WaitAny. 一开始你设置了一个WaitHandle[],每个人等待一个Task,当任务成功执行(并得到true你期望的结果)时,你发出相应的信号WaitHandle

于 2012-08-06T08:26:43.570 回答
1

您可以使用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();
}
于 2012-08-06T08:48:42.723 回答