不使用 async and await 实现 async and await
Implementing async and await without async and await
对于某些教程,我计划使用一些回调来解释 async
和 await
。基于 https://docs.microsoft.com/dotnet/csharp/programming-guide/concepts/async 我尝试使用回调实现类似的东西:
static void Main(string[] args)
{
Console.WriteLine("Lets start a delicious breakfast");
FryEggsCallback(2, () =>
{
Console.WriteLine("eggs are ready");
});
FryBaconCallback(3, () =>
{
Console.WriteLine("bacon is ready");
});
ToastBreadCallback(2, x =>
{
ApplyButter(x);
ApplyJam(x);
Console.WriteLine("toast is ready");
});
Console.WriteLine("Breakfast is ready!");
}
static void FryEggsCallback(int count, Action onReady)
{
Task.Delay(3000).Wait(); // simulate some work that should be done
onReady();
}
static void FryBaconCallback(int count, Action onReady)
{
Task.Delay(3000).Wait();
onReady();
}
static void ToastBreadCallback(int count, Action<Toast> onReady)
{
Task.Delay(3000).Wait();
onReady(new Toast());
}
但是 Task.Delay().Wait()
阻塞了我的线程,所以它们不是异步地 运行ning 三个调用,而是一个接一个地 运行 顺序调用。
我将如何使用回调异步实现这三个调用而不是使用 async
和 await
?
阻塞的不是 Task.Delay(x)
,而是 Task.Delay(x).Wait()
。
Task.Wait
会同步阻塞。
我会使用 Task.ContinueWith
在 Task.Delay
任务上链接一个延续,以便 onReady()
在任务完成时异步执行,即:
Task.Delay(3000).Wait();
...应该变成:
Task.Delay(3000).ContinueWith(x => onReady());
请注意,Task.Delay 只是定时器对象的包装器。因此,如果想在任务完成时进行回调,您的示例基本上可以归结为:
new Timer (o => Console.WriteLine("eggs are ready"), null, 3000, Timeout.Infinite);
new Timer (o => Console.WriteLine("bacon is ready"), null, 3000, Timeout.Infinite);
new Timer (o => {
var toast = new Toast();
ApplyButter(toast);
ApplyJam(toast);
Console.WriteLine("toast is ready");
}, null, 3000, Timeout.Infinite);
Console.WriteLine("Breakfast is ready!")
一个明显的问题是早餐在任何组成部分之前准备好。但也许更重要的是,它并没有解释如何 async
rewrites the method to a statemachine。所以我真的不确定这个例子应该教什么。
考虑一下您 link:
中的一个稍微简化的示例
Task<Egg> eggsTask = FryEggsAsync(2);
Task<Toast> toastTask = ToastBreadAsync(2);
Toast toast = await toastTask;
ApplyButter(toast);
ApplyJam(toast);
Console.WriteLine("Toast is ready");
Juice oj = PourOJ();
Console.WriteLine("Oj is ready");
Egg eggs = await eggsTask;
Console.WriteLine("Eggs are ready");
Console.WriteLine("Breakfast is ready!");
为了模拟这种行为,我们可以使用一个状态机来跟踪我们在准备工作中进行了多远,以及我们拥有哪些组件:
public Egg FriedEgg;
public Toast ToastedBread;
private int state = 0;
public void Run(){
switch(state){
case 0;
if(ToastedBread != null){
ApplyButter(ToastedBread )
ApplyJam(ToastedBread );
Console.WriteLine("Toast is ready");
Juice oj = PourOJ();
Console.WriteLine("Oj is ready");
state = 1;
Run(); // Continue to the next state if possible
}
break;
case 1:
if( FriedEgg != null){
Console.WriteLine("Eggs are ready");
state = 2;
Run(); // Continue to the next state if possible
}
break;
case 2:
Console.WriteLine("Breakfast is ready!");
state = 3;
break;
}
}
每个计时器回调都会设置相应的 Egg 或 Toast 字段并调用 Run
。因此,无论鸡蛋或烤面包是否先完成,它都会尽可能地继续准备工作。请注意,这只是为了演示概念,它缺少诸如线程安全之类的东西。
正如您可能看到的那样,幕后工作相当复杂,甚至没有涉及 synchronizationContexts。
对于某些教程,我计划使用一些回调来解释 async
和 await
。基于 https://docs.microsoft.com/dotnet/csharp/programming-guide/concepts/async 我尝试使用回调实现类似的东西:
static void Main(string[] args)
{
Console.WriteLine("Lets start a delicious breakfast");
FryEggsCallback(2, () =>
{
Console.WriteLine("eggs are ready");
});
FryBaconCallback(3, () =>
{
Console.WriteLine("bacon is ready");
});
ToastBreadCallback(2, x =>
{
ApplyButter(x);
ApplyJam(x);
Console.WriteLine("toast is ready");
});
Console.WriteLine("Breakfast is ready!");
}
static void FryEggsCallback(int count, Action onReady)
{
Task.Delay(3000).Wait(); // simulate some work that should be done
onReady();
}
static void FryBaconCallback(int count, Action onReady)
{
Task.Delay(3000).Wait();
onReady();
}
static void ToastBreadCallback(int count, Action<Toast> onReady)
{
Task.Delay(3000).Wait();
onReady(new Toast());
}
但是 Task.Delay().Wait()
阻塞了我的线程,所以它们不是异步地 运行ning 三个调用,而是一个接一个地 运行 顺序调用。
我将如何使用回调异步实现这三个调用而不是使用 async
和 await
?
阻塞的不是 Task.Delay(x)
,而是 Task.Delay(x).Wait()
。
Task.Wait
会同步阻塞。
我会使用 Task.ContinueWith
在 Task.Delay
任务上链接一个延续,以便 onReady()
在任务完成时异步执行,即:
Task.Delay(3000).Wait();
...应该变成:
Task.Delay(3000).ContinueWith(x => onReady());
请注意,Task.Delay 只是定时器对象的包装器。因此,如果想在任务完成时进行回调,您的示例基本上可以归结为:
new Timer (o => Console.WriteLine("eggs are ready"), null, 3000, Timeout.Infinite);
new Timer (o => Console.WriteLine("bacon is ready"), null, 3000, Timeout.Infinite);
new Timer (o => {
var toast = new Toast();
ApplyButter(toast);
ApplyJam(toast);
Console.WriteLine("toast is ready");
}, null, 3000, Timeout.Infinite);
Console.WriteLine("Breakfast is ready!")
一个明显的问题是早餐在任何组成部分之前准备好。但也许更重要的是,它并没有解释如何 async
rewrites the method to a statemachine。所以我真的不确定这个例子应该教什么。
考虑一下您 link:
中的一个稍微简化的示例Task<Egg> eggsTask = FryEggsAsync(2);
Task<Toast> toastTask = ToastBreadAsync(2);
Toast toast = await toastTask;
ApplyButter(toast);
ApplyJam(toast);
Console.WriteLine("Toast is ready");
Juice oj = PourOJ();
Console.WriteLine("Oj is ready");
Egg eggs = await eggsTask;
Console.WriteLine("Eggs are ready");
Console.WriteLine("Breakfast is ready!");
为了模拟这种行为,我们可以使用一个状态机来跟踪我们在准备工作中进行了多远,以及我们拥有哪些组件:
public Egg FriedEgg;
public Toast ToastedBread;
private int state = 0;
public void Run(){
switch(state){
case 0;
if(ToastedBread != null){
ApplyButter(ToastedBread )
ApplyJam(ToastedBread );
Console.WriteLine("Toast is ready");
Juice oj = PourOJ();
Console.WriteLine("Oj is ready");
state = 1;
Run(); // Continue to the next state if possible
}
break;
case 1:
if( FriedEgg != null){
Console.WriteLine("Eggs are ready");
state = 2;
Run(); // Continue to the next state if possible
}
break;
case 2:
Console.WriteLine("Breakfast is ready!");
state = 3;
break;
}
}
每个计时器回调都会设置相应的 Egg 或 Toast 字段并调用 Run
。因此,无论鸡蛋或烤面包是否先完成,它都会尽可能地继续准备工作。请注意,这只是为了演示概念,它缺少诸如线程安全之类的东西。
正如您可能看到的那样,幕后工作相当复杂,甚至没有涉及 synchronizationContexts。