C# 使用信号量LIM取消异步任务花费的时间太长

C# 使用信号量LIM取消异步任务花费的时间太长,c#,asynchronous,task-parallel-library,semaphore,cancellation-token,C#,Asynchronous,Task Parallel Library,Semaphore,Cancellation Token,场景是将大量不同类型的任务排队,限制它们进行并行处理,并能够取消它们。 我的问题是,由于所有任务都已经挂起在信号灯中,所以取消它们实际上比任务本身需要更长的时间 显然,.Run将所有任务都抛出到.WaitAsync中,因此其状态为WaitingForActivation。因此,给任务本身的标记实际上毫无意义:所有1000个任务都已经在运行 将令牌提供给WaitAsync似乎会在取消时冻结应用程序 静态信号量lim批处理程序=新信号量lim(5); 静态void Main(字符串[]参数) {

场景是将大量不同类型的任务排队,限制它们进行并行处理,并能够取消它们。 我的问题是,由于所有任务都已经挂起在信号灯中,所以取消它们实际上比任务本身需要更长的时间

显然,.Run将所有任务都抛出到.WaitAsync中,因此其状态为WaitingForActivation。因此,给任务本身的标记实际上毫无意义:所有1000个任务都已经在运行

将令牌提供给WaitAsync似乎会在取消时冻结应用程序

静态信号量lim批处理程序=新信号量lim(5);
静态void Main(字符串[]参数)
{            
var tokenStore=new CancellationTokenSource();
var tasks=Enumerable.Range(11000)。选择(i=>
DoableWork(tokenStore.Token)
).ToList();
做{
if(Console.KeyAvailable&&Console.ReadKey(true).Key==ConsoleKey.Escape){
Console.WriteLine(“取消任务”);
tokenStore.Cancel();
}
睡眠(1000);
Console.WriteLine($“任务:{string.Join(,”,Tasks.GroupBy(t=>t.Status)。选择(x=>$”{x.Count()}{x.Key}”))});
}而(tasks.Any(t=>t.Status{
试一试{
wait batcher.WaitAsync();
token.ThrowIfCancellationRequested();
等待任务。延迟(200,令牌);//执行任务
}捕获(操作取消异常){
投掷;
}捕获(例外){
//伐木
投掷;
}最后{
batcher.Release();
}
},代币);
}
结果:

Tasks: 25 RanToCompletion, 975 WaitingForActivation
Tasks: 50 RanToCompletion, 950 WaitingForActivation
Tasks: 75 RanToCompletion, 925 WaitingForActivation
Tasks: 100 RanToCompletion, 900 WaitingForActivation
Tasks: 120 RanToCompletion, 880 WaitingForActivation
Tasks: 145 RanToCompletion, 855 WaitingForActivation
Cancelling tasks
Tasks: 145 RanToCompletion, 16 Canceled, 839 WaitingForActivation
Tasks: 145 RanToCompletion, 33 Canceled, 822 WaitingForActivation
Tasks: 145 RanToCompletion, 51 Canceled, 804 WaitingForActivation
Tasks: 145 RanToCompletion, 66 Canceled, 789 WaitingForActivation
Tasks: 145 RanToCompletion, 81 Canceled, 774 WaitingForActivation
Tasks: 145 RanToCompletion, 101 Canceled, 754 WaitingForActivation
正如您所看到的,每秒取消的任务少于已处理的任务。按照这种速度,您将有整整一分钟的等待时间来取消1000个挂起的任务

使用new Task()进行替换并调用Task.Start()将导致中断取消机制,而不是从每个正在运行的任务中抛出未处理的异常

tasks.Where(t=>t.Statust.Status==TaskStatus.Running))
托利斯先生()
.ForEach(t=>t.Start());
私有静态任务DoableWork(CancellationToken令牌)
{
返回新任务(异步()=>{
试一试{
等待任务。延迟(200,令牌);//执行任务
}捕获(操作取消异常){
投掷;
}捕获(例外){
//伐木
投掷;
}
},代币);
}

找到了问题。VS2019(或其设置之一)在调试模式下显著降低了异常处理的速度。当我直接运行.exe时,取消是即时的。
感谢@TheodorZoulias未能再现问题。

t.Status
。我认为我们不应该像那样使用枚举。早期版本有一个任务。WhenAll()。不管怎样,这都不是问题的关键。问题是WaitAsync处理取消时捕获的任务比happyflow任务花费的时间更长。试试这个程序,然后做一个取消,你会看到的,我会试试。但与此同时,我们来看看一种更好的并行节流设计,它使用了
信号量lim
:。他没有一次启动1000个热门任务,而是在信号量的
WaitAsync
之后一个接一个地启动它们。这一点很好。他已经在忙着沿着这条路线继续下去解决问题。Thanks@TheodorZoulias谢谢,我找到问题了。VS2019(或其设置之一)在调试模式下显著降低了异常处理的速度。当我直接运行.exe时,取消也是即时的。