static void DoSomething(int id) { Thread.Sleep(50); Console.WriteLine(@"DidSomething({0})",id); }
我知道我可以将它转换为异步任务,如下所示:
static async Task DoSomethingAsync(int id) { await Task.Delay(50); Console.WriteLine(@"DidSomethingAsync({0})",id); }
而且,如果我多次呼叫(Task.WhenAll),所有这一切将比使用Parallel.Foreach甚至在循环中调用更快更有效率.
但是一会儿,假装Task.Delay()不存在,我实际上必须使用Thread.Sleep();我知道现实情况并非如此,但这是概念代码,延迟/睡眠通常是没有async选项(如早期EF)的IO操作.
我尝试过以下内容
static async Task DoSomethingAsync2(int id) { await Task.Run(() => { Thread.Sleep(50); Console.WriteLine(@"DidSomethingAsync({0})",id); }); }
但是,尽管它运行没有错误,根据Lucien Wischik,这实际上是不好的做法,因为它只是从池中旋转线程来完成每个任务(使用以下控制台应用程序也是较慢的 – 如果在DoSomethingAsync和DoSomethingAsync2调用之间进行交换您可以看到完成所需的时间有显着差异)
static void Main(string[] args) { MainAsync(args).Wait(); } static async Task MainAsync(String[] args) { List<Task> tasks = new List<Task>(); for (int i = 1; i <= 1000; i++) tasks.Add(DoSomethingAsync2(i)); // Can replace with any version await Task.WhenAll(tasks); }
然后我尝试了以下内容
static async Task DoSomethingAsync3(int id) { await new Task(() => { Thread.Sleep(50); Console.WriteLine(@"DidSomethingAsync({0})",id); }); }
移植这个代替原来的DoSomethingAsync,测试从未完成,屏幕上没有显示任何内容!
我也尝试了多个其他变体,不编译或不完成!
所以,考虑到你不能调用任何现有的异步方法,并且必须在异步任务中完成Thread.Sleep和Console.WriteLine的约束,你如何以与原始代码一样的方式来执行它?
对于那些有兴趣的人来说,这个目标是让我更好地了解如何创建我自己的异步方法,我不会打电话给任何人.尽管有许多搜索,这似乎是一个真正缺少示例的领域 – 而且有数千个调用异步方法的例子可以调用其他异步方法,我无法找到将现有的void方法转换为异步任务的任何方法除了使用Task.Run(()=> {})方法之外,还没有调用进一步的异步任务.
解决方法
您要查找的是TaskCompletionSource< T>.对于常见情况,有各种“速记”形式,因此您不必总是使用TaskCompletionSource< T>直.例如Task.FromResult或TaskFactory.FromAsync.如果您现有的* Begin / * End实现了I / O,则FromAsync最常用;否则,您可以使用TaskCompletionSource< T>直.
有关更多信息,请参阅Implementing the Task-based Asynchronous Pattern的“I / O绑定任务”部分.
(不幸的是)Task任务的构造函数是从基于任务的并行性中断的,不应该用在异步代码中.它只能用于创建基于代码的任务,而不是外部事件任务.
So,given the constraint that you cannot call any existing asynchronous methods and must complete both the Thread.Sleep and the Console.WriteLine in an asynchronous task,how do you do it in a manner that is as efficient as the original code?
我会使用某种类型的计时器,并使其完成TaskCompletionSource< T>定时器触发.我几乎是积极的,这是实际的Task.Delay实现.