我有一些返回bool的任务。我只想等到任何任务首先返回True。可能吗 ?
我的第一个想法是使用CancellationTokenSource,但这不是一个好主意,因为它在我调用Task.WaitAll方法时抛出异常。
第二个选项是使用我在参考中传递的bool,如果是,则直接返回。它有效,但它不具备性能:
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;
但它不起作用:(
答案 0 :(得分:4)
一种选择是创建所需类型的TaskCompletionSource
(如果需要,则识别结果)。然后为每个任务添加一个延续,如果结果为真,则调用TaskCompletionSource.TrySetResult
。
然后等待TaskCompletionSource.Task
。它避免了你不得不反复调用Task.WaitAny
,检查结果等。
当所有任务都返回false时,这一点很棘手......在.NET 4.5中,通过Task.WhenAll
创建另一个任务会相当容易 - 那么你只需要等待{ success, all failed }
的第一个完成。
答案 1 :(得分:3)
您需要WaitHandle.WaitAny
。在开始时,您设置了WaitHandle[]
,每个人等待Task
,当任务成功执行时(并按预期得到true
),您发出相应的信号WaitHandle
。
答案 2 :(得分: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();
}