C# .NET CORE:如果一个任务返回某种结果则取消其他任务
C# .NET CORE: cancell other tasks if one returned some kind of result
如何取消所有任务,如果其中一项任务 return 即 false (bool) 结果?
是否可以确定哪个任务 return 产生了结果?
class Program
{
private static Random _rnd = new Random();
static void Main(string[] args)
{
var tasksCounter = _rnd.Next(4, 7);
var cts = new CancellationTokenSource();
var tasks = new Task<bool>[tasksCounter];
for (int i = 0; i < tasks.Length; i++)
{
tasks[i] = CreateTask(cts);
}
Console.WriteLine("Waiting..");
Task.WaitAny(tasks);
Console.WriteLine("Done!");
Console.ReadKey();
}
private static Task<bool> CreateTask(CancellationTokenSource cts)
{
return Task.Factory.StartNew(TaskAction, cts.Token).Unwrap();
}
private static async Task<bool> TaskAction()
{
var delay = _rnd.Next(2, 5);
await Task.Delay(delay * 1000);
var taskResult = _rnd.Next(10) < 4;
return await Task.FromResult(taskResult);
}
}
我尝试使用 Task.WaitAll、Task.WaitAny 等,但是 none 这些方法提供了有用的(对我而言)功能。
我手边没有翻译,如有错误请见谅。如果您想从任务本身取消所有任务,您的任务需要访问令牌。有关示例,请参见 https://docs.microsoft.com/en-us/dotnet/api/system.threading.cancellationtokensource?view=netcore-3.0。 IE。将其作为参数传递给任务,以便一个任务可以取消其他任务。
private static async Task<bool> TaskAction(CancellationTokenSource cts)
{
var delay = _rnd.Next(2, 5);
await Task.Delay(delay * 1000);
var taskResult = _rnd.Next(10) < 4;
if (!taskResult)
cts.Cancel()
return await Task.FromResult(taskResult);
}
只需确保捕获 AggregateException
并检查内部异常之一是否为 TaskCanceledException
。
编辑:
正如 @ckuri 在评论中所述,利用 Task
的现有属性而不是编写自定义结果 class 会更容易。相应地调整了我的答案。
一种解决方案是检查 CreateTask()
方法中的结果并将 CancellationToken
传递到您的 TaskAction()
方法中:
private static Task<bool> CreateTask(CancellationTokenSource cts)
{
return Task.Run(async () =>
{
var result = await TaskAction(cts.Token);
// If result is false, cancel all tasks
if (!result)
cts.Cancel();
return result;
});
}
private static async Task<bool> TaskAction(CancellationToken token)
{
// Check for cancellation
token.ThrowIfCancellationRequested();
var delay = Rnd.Next(2, 5);
// Pass the cancellation token to Task.Delay()
await Task.Delay(delay * 1000, token);
var taskResult = Rnd.Next(10) < 4;
// Check for cancellation
token.ThrowIfCancellationRequested();
return taskResult;
}
现在您可以在 Main
方法中执行类似的操作来接收所有未取消的任务:
try
{
// Wait for all tasks inside a try catch block because `WhenAll` throws a `AggregationException`
// containing a `TaskCanceledException`, if the token gets canceled
await Task.WhenAll(tasks);
}
catch { }
var tasksWithResult = tasks.Where(t => !t.IsCanceled).ToList();
如何取消所有任务,如果其中一项任务 return 即 false (bool) 结果? 是否可以确定哪个任务 return 产生了结果?
class Program
{
private static Random _rnd = new Random();
static void Main(string[] args)
{
var tasksCounter = _rnd.Next(4, 7);
var cts = new CancellationTokenSource();
var tasks = new Task<bool>[tasksCounter];
for (int i = 0; i < tasks.Length; i++)
{
tasks[i] = CreateTask(cts);
}
Console.WriteLine("Waiting..");
Task.WaitAny(tasks);
Console.WriteLine("Done!");
Console.ReadKey();
}
private static Task<bool> CreateTask(CancellationTokenSource cts)
{
return Task.Factory.StartNew(TaskAction, cts.Token).Unwrap();
}
private static async Task<bool> TaskAction()
{
var delay = _rnd.Next(2, 5);
await Task.Delay(delay * 1000);
var taskResult = _rnd.Next(10) < 4;
return await Task.FromResult(taskResult);
}
}
我尝试使用 Task.WaitAll、Task.WaitAny 等,但是 none 这些方法提供了有用的(对我而言)功能。
我手边没有翻译,如有错误请见谅。如果您想从任务本身取消所有任务,您的任务需要访问令牌。有关示例,请参见 https://docs.microsoft.com/en-us/dotnet/api/system.threading.cancellationtokensource?view=netcore-3.0。 IE。将其作为参数传递给任务,以便一个任务可以取消其他任务。
private static async Task<bool> TaskAction(CancellationTokenSource cts)
{
var delay = _rnd.Next(2, 5);
await Task.Delay(delay * 1000);
var taskResult = _rnd.Next(10) < 4;
if (!taskResult)
cts.Cancel()
return await Task.FromResult(taskResult);
}
只需确保捕获 AggregateException
并检查内部异常之一是否为 TaskCanceledException
。
编辑:
正如 @ckuri 在评论中所述,利用 Task
的现有属性而不是编写自定义结果 class 会更容易。相应地调整了我的答案。
一种解决方案是检查 CreateTask()
方法中的结果并将 CancellationToken
传递到您的 TaskAction()
方法中:
private static Task<bool> CreateTask(CancellationTokenSource cts)
{
return Task.Run(async () =>
{
var result = await TaskAction(cts.Token);
// If result is false, cancel all tasks
if (!result)
cts.Cancel();
return result;
});
}
private static async Task<bool> TaskAction(CancellationToken token)
{
// Check for cancellation
token.ThrowIfCancellationRequested();
var delay = Rnd.Next(2, 5);
// Pass the cancellation token to Task.Delay()
await Task.Delay(delay * 1000, token);
var taskResult = Rnd.Next(10) < 4;
// Check for cancellation
token.ThrowIfCancellationRequested();
return taskResult;
}
现在您可以在 Main
方法中执行类似的操作来接收所有未取消的任务:
try
{
// Wait for all tasks inside a try catch block because `WhenAll` throws a `AggregationException`
// containing a `TaskCanceledException`, if the token gets canceled
await Task.WhenAll(tasks);
}
catch { }
var tasksWithResult = tasks.Where(t => !t.IsCanceled).ToList();