如何在C#中当一个任务完成时停止所有任务

6

我有不同的任务需要从不同的文件中读取并查找单词。我将它们放入一个任务数组中,并使用waitAny方法开始执行,如下所示:

foreach (string file in filesList)
        {
            files[i] = Task.Factory.StartNew(() =>
            {
                mySearch.Invoke(file);
            });
            i++;
        }
        System.Threading.Tasks.Task.WaitAny(files);

我希望在其中一个任务完成时停止所有其他任务(当它找到单词时即表示完成)。目前,使用waitany,我可以知道一个任务何时完成,但是我不知道如何知道哪一个已经完成以及如何停止其他任务。最好的方法是什么?

已完成的任务是否在某个地方留下了结果?这可能包括任务的标识。完成的第一个任务也可以设置一个事件,在其主循环中检查,这将导致所有其他任务退出。 - HABO
在mySearch.Invoke中,应该有一个循环逐字遍历。然后您可以添加一个标志,以便当标志被触发时循环中断,当任何任务找到单词时,您可以触发该标志。 - ComfortablyNumb
3个回答

3

您可以使用单个 CancellationToken,所有任务都将共享。在 mySearch.Invoke 方法中验证 token.IsCancellationRequested 的值以取消任务。当某个任务完成后,通过 CancellationTokenSource.Cancel() 取消其他任务。

var tokenSource = new CancellationTokenSource();
var token = tokenSource.Token; 

foreach (string file in filesList)
{
   // pass cancellation token to your task
   files[i] = Task.Factory.StartNew(() => mySearch.Invoke(file, token), token);
   i++;
}

Task.WaitAny(files);
tokenSource.Cancel();

顺便说一下,您可以通过调用token.ThrowIfCancellationRequested()来强制令牌在源被取消时抛出OperationCanceledException


2
创建任务时,您可以传递一个CancelationToken。当其中一个任务完成时,请设置此令牌。这将导致具有此令牌的剩余任务不执行。正在运行的任务也可以接收OperationCanceledException并停止。

1

我强烈建议阅读 Stephen Toub 的 如何取消不可取消的异步操作?。基本上,您需要做的是取消所有这些任务,但目前您没有取消它们的机制。

理想的方法是在 foreach 之前创建一个 CancellationTokenSource,将来自该源的 CancellationToken 传递给每个子任务,在定期检查该令牌并注意到其已指示取消时停止执行工作。然后您可以在 WhenAny 继续中取消令牌源。

如果这不是选项,则需要决定是否重要实际停止任务(事实上,这根本无法完成)或者您只需要继续您的代码而不必等待它们完成(这很容易实现)。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接