【发布时间】:2014-03-15 01:25:03
【问题描述】:
给定以下代码...
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();我知道实际上情况并非如此,但这是概念代码,延迟/睡眠所在的位置通常是没有异步选项(例如早期 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(() => {} ) 方法的任务之外,没有对进一步异步任务的调用。
【问题讨论】:
-
你的最后一个例子永远不会完成,因为你从来没有在你创建的任务上调用
Start。 -
@lee:如果我 await new Task(()=> {}).Start() 不会编译,因为 Task.Start() 返回 void。
-
如果您需要在不阻塞线程的情况下以高效的方式等待,您可以使用TaskCompletionSource。
-
您需要先启动任务,然后再尝试
await。var task = new Task(...); task.Start(); await task; -
@lee: 也试过静态异步任务 DoSomethingAsync2(int id) { Task task = new Task(() => { Thread.Sleep(50); Console.WriteLine(@"DidSomethingAsync({0 })“, ID); });任务.开始();等待任务; } 但这与 DoSomethingAsync2 示例一样慢。
标签: c# .net .net-4.5 async-await c#-5.0