给定以下代码...
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();我知道实际上情况并非如此,但这是概念代码,延迟/ sleep 通常是没有异步选项的 IO 操作(例如早期的 EF)。
我尝试了以下...
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(() => {} ) 方法的任务之外,没有调用进一步的异步任务。
最佳答案
有两种任务:执行代码的任务(例如,Task.Run
和 friend ),以及响应某些外部事件的任务(例如,TaskCompletionSource<T>
和 friend )。
您要找的是TaskCompletionSource<T>
.常见情况有多种“速记”形式,因此您不必总是使用 TaskCompletionSource<T>
直接地。例如,Task.FromResult
或 TaskFactory.FromAsync
. FromAsync
如果您有现有的 *Begin
,则最常用/*End
实现您的 I/O;否则,您可以使用 TaskCompletionSource<T>
直接。
有关详细信息,请参阅 Implementing the Task-based Asynchronous Pattern 的“I/O 绑定(bind)任务”部分.
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
实现无论如何。
关于c# - 如何将其转换为异步任务?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/21800450/