等待任务不等待

编程入门 行业动态 更新时间:2024-10-26 12:23:01
本文介绍了等待任务不等待的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧! 问题描述

我有一个简单的通用节气门功能的MS文档实现形式.

I have a simple taken form MS documentation implementation of generic throttle function.

public async Task RunTasks(List<Task> actions, int maxThreads) { var queue = new ConcurrentQueue<Task>(actions); var tasks = new List<Task>(); for (int n = 0; n < maxThreads; n++) { tasks.Add(Task.Run(async () => { while (queue.TryDequeue(out Task action)) { action.Start(); await action; int i = 9; //this should not be reached. } })); } await Task.WhenAll(tasks); }

要测试它,我有一个单元测试:

To test it I have a unit test:

[Fact] public async Task TaskRunningLogicThrottles1() { var tasks = new List<Task>(); const int limit = 2; for (int i = 0; i < 2000; i++) { var task = new Task(async () => { await Task.Delay(-1); }); tasks.Add(task); } await _logic.RunTasks(tasks, limit); }

由于任务中存在Delay(-1),因此该测试永远都无法完成.行"int y = 9;"表示行.在RunTasks函数中应该永远都不能达到.但是,它确实起作用了,而我的整个功能却无法执行应做的工作-节流执行.如果相反,还是等待Task.Delay(),我使用了同步Thread.Sleep,则可以正常工作.

Since there is a Delay(-1) in the tasks this test should never complete. The line "int y = 9;" in the RunTasks function should never be reached. However it does and my whole function fails to do what it is supposed to do - throttle execution. If instead or await Task.Delay() I used synchronous Thread.Sleep ot works as exptected.

推荐答案

Task 类没有构造函数,因此您传递给它的异步委托为">代码无效 .这是一个常见的陷阱.仅仅因为编译器允许我们向任何lambda添加 async 关键字,并不意味着我们应该这样做.我们应该仅将异步lambda传递给期望并理解它们的方法,这意味着参数的类型应为 Func ,其返回值为 Task .例如 Func< Task> ,或 Func< Task< T>> ,或 Func< TSource,Task< TResult>> 等

The Task class has no constructor that accepts async delegates, so the async delegate you passed to it is async void. This is a common trap. Just because the compiler allows us to add the async keyword to any lambda, doesn't mean that we should. We should only pass async lambdas to methods that expect and understand them, meaning that the type of the parameter should be a Func with a Task return value. For example Func<Task>, or Func<Task<T>>, or Func<TSource, Task<TResult>> etc.

您可以 要做的是将异步lambda传递给 Task< TResult> 构造函数,在这种情况下,将解析 TResult 作为 Task .换句话说,您可以创建嵌套的 Task< Task> 实例:

What you could do is to pass the async lambda to a Task<TResult> constructor, in which case the TResult would be resolved as Task. In other words you could create nested Task<Task> instances:

var taskTask = new Task<Task>(async () => { await Task.Delay(-1); });

这样,您将有一个很酷的外部任务,即在启动时将创建内部任务.创建任务所需的工作可以忽略不计,因此将立即创建内部任务.内部任务将是一个Promise样式的任务,就像异步方法生成的所有任务一样.承诺式任务在创建时总是很热门.不能像基于委托的任务那样在冷状态下创建它.调用其 Start 方法会导致 InvalidOperationException .

This way you would have a cold outer task, that when started would create the inner task. The work required to create a task is negligible, so the inner task will be created instantly. The inner task would be a promise-style task, like all tasks generated by async methods. A promise-style task is always hot on creation. It cannot be created in a cold state like a delegate-based task. Calling its Start method results to an InvalidOperationException.

创建冷任务和嵌套任务是一种高级技术,在实践中很少使用.按需启动promise样式任务的常用技术是将它们作为异步委托传递(各种口味的 Func< Task> 实例),然后在适当的时候调用每个委托.

Creating cold tasks and nested tasks is an advanced technique that is used rarely in practice. The common technique for starting promise-style tasks on demand is to pass them around as async delegates (Func<Task> instances in various flavors), and invoke each delegate at the right moment.

更多推荐

等待任务不等待

本文发布于:2023-11-06 09:58:09,感谢您对本站的认可!
本文链接:https://www.elefans.com/category/jswz/34/1563380.html
版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系,我们将在24小时内删除。
本文标签:

发布评论

评论列表 (有 0 条评论)
草根站长

>www.elefans.com

编程频道|电子爱好者 - 技术资讯及电子产品介绍!