为什么 Main 不等待所有线程在异步程序中求值?
Why does Main not wait for all threads to evaluate in asynchronous program?
@Dan Dinu 在之前关于 C# 异步编程的问题中的回答提供了一个有用的最小示例,我将其改编如下:
// From
using System;
using System.Threading.Tasks;
namespace minimal_async_await_SE
{
internal class Program
{
public static async Task MyMethodAsync()
{
Task<int> longRunningTask = LongRunningOperationAsync();
// independent work which doesn't need the result of LongRunningOperationAsync
// can be done here
Console.WriteLine("Independent work");
//Call await on the task
int result = await longRunningTask;
Console.WriteLine(result);
}
public static async Task<int> LongRunningOperationAsync()
{
await Task.Delay(1000);
return 1;
}
static void Main(string[] args)
{
MyMethodAsync();
Console.WriteLine("Returned to Main");
//Console.ReadKey();
}
}
}
如果我取消注释第 32 行,我会得到以下预期结果:
Independent work
Returned to Main
1
基本上:
Main
呼叫 MyMethodAsync
MyMethodAsync
呼叫 LongRunningOperationAsync
LongRunningOperationAsync
然后调用 Task.Delay
,但是 await
它暂停了对封闭方法 LongRunningOperationAsync
的进一步评估,将控制权返回给调用者,即 MyMethodAsync
.
MyMethodAsync
打印出 "Independent work"
.
MyMethodAsync
尝试分配 LongRunningOperation to
resultbut
awaits it, suspends evaluation of the enclosing
MyMethodAsync, and returns control of the program back to
Main` 的结果
Main
打印出 "Returned to Main"
Task.Delay(1000)
在 LongRunningOperationAsync()
完成
- 产生了一个新线程,在
LongRunningOperationAsync
(MyMethodAsync
) 的调用者中,整数 1
被分配给 result
.
MyMethodAsync
的计算完成,MyMethodAsync
打印出 result
的值
- 控制权交还给
Main
,这会暂停计算,直到用户通过 Console.ReadKey
输入密钥
首先,我对这个程序如何求值的理解正确吗?其次,为什么我在评论Console.ReadKey
的时候,会得到如下意想不到的结果?
Independent work
Returned to Main
Main
方法是否在退出程序之前不等待所有线程都得到评估?为什么或为什么不?
“为什么或为什么不?”问题的答案。很复杂,但可以通过更好地理解 Task
.
来回答
A Task
不是线程。许多任务可以 运行 在单个线程上,单个任务可以 运行 在多个线程上。
任务更像是一个事件,它会触发调度程序 运行 在当时可用的任何线程上执行一些代码(忽略一些复杂的延续问题)
所以您的问题可能是re-phrased“为什么我的程序不监听所有事件并在所有事件都触发之前阻止执行?”。这个问题的答案可能让 1 或 2 个 TPL(任务)的设计者彻夜难眠,最终他们认为这个决定的影响有可能对其他类型的应用程序造成一些严重的伤害
TPL 的设计者确实为我们提供了解决此问题的方法(后来的几个 C# 版本),即异步 Main 方法。在您的情况下,它看起来像这样:
static async Task Main(string[] args)
{
await MyMethodAsync();
Console.WriteLine("Returned to Main");
}
@Dan Dinu 在之前关于 C# 异步编程的问题中的回答提供了一个有用的最小示例,我将其改编如下:
// From
using System;
using System.Threading.Tasks;
namespace minimal_async_await_SE
{
internal class Program
{
public static async Task MyMethodAsync()
{
Task<int> longRunningTask = LongRunningOperationAsync();
// independent work which doesn't need the result of LongRunningOperationAsync
// can be done here
Console.WriteLine("Independent work");
//Call await on the task
int result = await longRunningTask;
Console.WriteLine(result);
}
public static async Task<int> LongRunningOperationAsync()
{
await Task.Delay(1000);
return 1;
}
static void Main(string[] args)
{
MyMethodAsync();
Console.WriteLine("Returned to Main");
//Console.ReadKey();
}
}
}
如果我取消注释第 32 行,我会得到以下预期结果:
Independent work
Returned to Main
1
基本上:
Main
呼叫MyMethodAsync
MyMethodAsync
呼叫LongRunningOperationAsync
LongRunningOperationAsync
然后调用Task.Delay
,但是await
它暂停了对封闭方法LongRunningOperationAsync
的进一步评估,将控制权返回给调用者,即MyMethodAsync
.MyMethodAsync
打印出"Independent work"
.MyMethodAsync
尝试分配LongRunningOperation to
resultbut
awaits it, suspends evaluation of the enclosing
MyMethodAsync, and returns control of the program back to
Main` 的结果
Main
打印出"Returned to Main"
Task.Delay(1000)
在LongRunningOperationAsync()
完成- 产生了一个新线程,在
LongRunningOperationAsync
(MyMethodAsync
) 的调用者中,整数1
被分配给result
. MyMethodAsync
的计算完成,MyMethodAsync
打印出result
的值
- 控制权交还给
Main
,这会暂停计算,直到用户通过Console.ReadKey
输入密钥
首先,我对这个程序如何求值的理解正确吗?其次,为什么我在评论Console.ReadKey
的时候,会得到如下意想不到的结果?
Independent work
Returned to Main
Main
方法是否在退出程序之前不等待所有线程都得到评估?为什么或为什么不?
“为什么或为什么不?”问题的答案。很复杂,但可以通过更好地理解 Task
.
A Task
不是线程。许多任务可以 运行 在单个线程上,单个任务可以 运行 在多个线程上。
任务更像是一个事件,它会触发调度程序 运行 在当时可用的任何线程上执行一些代码(忽略一些复杂的延续问题)
所以您的问题可能是re-phrased“为什么我的程序不监听所有事件并在所有事件都触发之前阻止执行?”。这个问题的答案可能让 1 或 2 个 TPL(任务)的设计者彻夜难眠,最终他们认为这个决定的影响有可能对其他类型的应用程序造成一些严重的伤害
TPL 的设计者确实为我们提供了解决此问题的方法(后来的几个 C# 版本),即异步 Main 方法。在您的情况下,它看起来像这样:
static async Task Main(string[] args)
{
await MyMethodAsync();
Console.WriteLine("Returned to Main");
}