返回结果后,控制流如何保留在异步方法范围内?这类似于变量的闭包吗?
How does control flow remain in the async method scope after it has returned the result? Is this similar to closure for variables?
在下面的代码中,42 在 "Almost done" 之前打印到控制台。既然42已经被return编辑了,怎么控件还在AsyncCheck
?我知道如果任务在 'await' 时还没有完成,它将 return 控制但是这里我有一个明确的 return 声明,所以我很难理解这个.
async static Task<int> AsyncCheck()
{
await Task.Factory.StartNew( async () =>
{
Console.WriteLine("Start awesome work");
await Task.Delay(1000);
Console.WriteLine("Almost done");
await Task.Delay(1000);
Console.WriteLine("Ok, done!");
});
return 42;
}
async static void AsyncCall()
{
int result = await AsyncCheck();
Console.WriteLine(result);
}
我正在使用 'async void' 来检查这个示例。
您不应该将 Task.Factory.StartNew
与 async-await
一起使用。您应该使用 Task.Run
。 Task.Factory.StartNew
出现在 .Net 4.0 中,但没有考虑 async-await
。您仍然可以使用它,但除非您有充分的理由,否则 Task.Run
是一个更安全的选择。
不是返回 Task
,而是 returns 一个 Task<Task>
,您需要在等待之前解包:
Task<Task> task = Task.Factory.StartNew( async () =>
{
Console.WriteLine("Start awesome work");
await Task.Delay(1000);
Console.WriteLine("Almost done");
await Task.Delay(1000);
Console.WriteLine("Ok, done!");
});
Task unwrappedTask = task.Unwrap();
await unwrappedTask
没有它,您就不会真正等待 lambda 完成。您所做的只是使用 ThreadPool
线程来启动此异步方法。
基本上,您是在代码流继续进行的同时在不同的线程上并行执行 lambda。这就是为什么您在 "Almost done"
之前看到“42”
让我们脱糖吧!你有
async static Task<int> AsyncCheck()
{
await Task.Factory.StartNew( async () =>
{
Console.WriteLine("Start awesome work");
await Task.Delay(1000);
Console.WriteLine("Almost done");
await Task.Delay(1000);
Console.WriteLine("Ok, done!");
});
return 42;
}
async static void AsyncCall()
{
int result = await AsyncCheck();
Console.WriteLine(result);
}
编译器将其转换为以下内容:
static Task<int> AsyncCheck()
{
Task t = Task.Factory.StartNew( () =>
{
Console.WriteLine("Start awesome work");
Task d1 = Task.Delay(1000);
d1.ContinueWith(t1 => {
Console.WriteLine("Almost done");
Task t2 = Task.Delay(1000);
t2.ContinueWith( tt2 => {
Console.WriteLine("Ok, done!");
}
}
});
//no dependecies on t, so just return straight away
return Task.FromResult(42);
}
static void AsyncCall()
{
Task<int> result = AsyncCheck();
result.ContinueWith( t => {
Console.WriteLine(t.Result);
})
}
一旦任务完成,ContinueWith
将 运行 它的正文。这应该使控制流程清晰。
在下面的代码中,42 在 "Almost done" 之前打印到控制台。既然42已经被return编辑了,怎么控件还在AsyncCheck
?我知道如果任务在 'await' 时还没有完成,它将 return 控制但是这里我有一个明确的 return 声明,所以我很难理解这个.
async static Task<int> AsyncCheck()
{
await Task.Factory.StartNew( async () =>
{
Console.WriteLine("Start awesome work");
await Task.Delay(1000);
Console.WriteLine("Almost done");
await Task.Delay(1000);
Console.WriteLine("Ok, done!");
});
return 42;
}
async static void AsyncCall()
{
int result = await AsyncCheck();
Console.WriteLine(result);
}
我正在使用 'async void' 来检查这个示例。
您不应该将 Task.Factory.StartNew
与 async-await
一起使用。您应该使用 Task.Run
。 Task.Factory.StartNew
出现在 .Net 4.0 中,但没有考虑 async-await
。您仍然可以使用它,但除非您有充分的理由,否则 Task.Run
是一个更安全的选择。
不是返回 Task
,而是 returns 一个 Task<Task>
,您需要在等待之前解包:
Task<Task> task = Task.Factory.StartNew( async () =>
{
Console.WriteLine("Start awesome work");
await Task.Delay(1000);
Console.WriteLine("Almost done");
await Task.Delay(1000);
Console.WriteLine("Ok, done!");
});
Task unwrappedTask = task.Unwrap();
await unwrappedTask
没有它,您就不会真正等待 lambda 完成。您所做的只是使用 ThreadPool
线程来启动此异步方法。
基本上,您是在代码流继续进行的同时在不同的线程上并行执行 lambda。这就是为什么您在 "Almost done"
之前看到“42”让我们脱糖吧!你有
async static Task<int> AsyncCheck()
{
await Task.Factory.StartNew( async () =>
{
Console.WriteLine("Start awesome work");
await Task.Delay(1000);
Console.WriteLine("Almost done");
await Task.Delay(1000);
Console.WriteLine("Ok, done!");
});
return 42;
}
async static void AsyncCall()
{
int result = await AsyncCheck();
Console.WriteLine(result);
}
编译器将其转换为以下内容:
static Task<int> AsyncCheck()
{
Task t = Task.Factory.StartNew( () =>
{
Console.WriteLine("Start awesome work");
Task d1 = Task.Delay(1000);
d1.ContinueWith(t1 => {
Console.WriteLine("Almost done");
Task t2 = Task.Delay(1000);
t2.ContinueWith( tt2 => {
Console.WriteLine("Ok, done!");
}
}
});
//no dependecies on t, so just return straight away
return Task.FromResult(42);
}
static void AsyncCall()
{
Task<int> result = AsyncCheck();
result.ContinueWith( t => {
Console.WriteLine(t.Result);
})
}
一旦任务完成,ContinueWith
将 运行 它的正文。这应该使控制流程清晰。