https://www.cnblogs.com/sjyforg/p/3949029.html
看到大佬的文章,小弟来测试下
1.winform应用程序
private void button94_Click(object sender, EventArgs e)
{
TestAsync();
}
private async void TestAsync()
{
Console.WriteLine($"主线程调用异步之前ID{Thread.CurrentThread.ManagedThreadId}执行");
await Test();
Console.WriteLine($"异步后的线程ID{Thread.CurrentThread.ManagedThreadId}同步上下文:{SynchronizationContext.Current?.ToString()}开始执行");
}
private static Logger logger = LogManager.GetCurrentClassLogger();
private async Task Test()
{
await GetHoliday("2021-01");
}
private async Task GetHoliday(string date)
{
WebClient client = new WebClient();
client.Encoding = Encoding.UTF8;
var url = $"https://sp0.baidu.com/8aQDcjqpAAV3otqbppnN2DJv/api.php?query={date}&resource_id=6018";
var jsondata =await client.DownloadStringTaskAsync(url);
}
输出
主线程调用异步之前ID1执行
异步后的线程ID1同步上下文:System.Windows.Forms.WindowsFormsSynchronizationContext开始执行
可以看出:调用之前ID为1,调用以后线程ID为1,同步上下文为 System.Windows.Forms.WindowsFormsSynchronizationContext.
经过多次测试:调用前后线程ID一样。
2.控制台程序
static void Main(string[] args)
{
TestAsync();
Console.ReadKey();
}
private static async void TestAsync()
{
Console.WriteLine($"调用异步之前ID{Thread.CurrentThread.ManagedThreadId}执行");
await Test();
Console.WriteLine($"异步后的线程ID{Thread.CurrentThread.ManagedThreadId}同步上下文:{SynchronizationContext.Current?.ToString()}开始执行");
}
private static Logger logger = LogManager.GetCurrentClassLogger();
private static async Task Test()
{
try
{
await GetHoliday("2021-01");
}
catch (Exception e)
{
Console.WriteLine(e);
}
}
private static async Task GetHoliday(string date)
{
WebClient client = new WebClient();
client.Encoding = Encoding.UTF8;
var url = $"https://sp0.baidu.com/8aQDcjqpAAV3otqbppnN2DJv/api.php?query={date}&resource_id=6018";
var jsondata = await client.DownloadStringTaskAsync(url);
}
输出日志:
可以看出:调用之前ID为1,调用以后线程ID为11,同步上下文为 null.
经过多次测试:调用前后线程ID不一样。
3.Asp.net WebApi
public async Task<string> getPATData([FromUri]PATQuery patQuery)
{
try
{
Logs.Info($"主线程调用异步之前ID{Thread.CurrentThread.ManagedThreadId}执行");
var data = new
{
list = await patService.GetPAT(patQuery),
total = patQuery.records,
};
Logs.Info($"异步后的线程ID{Thread.CurrentThread.ManagedThreadId}同步上下文:{SynchronizationContext.Current?.ToString()}开始执行");
return data.ToJson();
}
catch (Exception e)
{
Logs.LogWriter(e.GetOriginalException());
}
return string.Empty;
}
输出日志:
2022-03-05 14:07:23.2669 INFO 主线程调用异步之前ID12执行
2022-03-05 14:07:24.0974 INFO 异步后的线程ID11同步上下文:System.Web.LegacyAspNetSynchronizationContext开始执行
2022-03-05 14:07:24.6551 INFO 主线程调用异步之前ID9执行
2022-03-05 14:07:25.4546 INFO 异步后的线程ID9同步上下文:System.Web.LegacyAspNetSynchronizationContext开始执行
可以看出:
第一次调用之前ID为12,调用以后线程ID为11,同步上下文为 System.Web.LegacyAspNetSynchronizationContext
第二次调用之前ID为9,调用以后线程ID为9,同步上下文为 System.Web.LegacyAspNetSynchronizationContext
经过多次测试:调用前后线程ID可能一样可能不一样。
第二次调用前后线程ID一样,可能的原因:使用 await 关键字,执行到真正的async方法(比如:ToListAsync()),当前线程立马被释放回线程池,线程的上下文信息会被保存。当 async 中的异步任务执行完成后,会获取当初调用者所在线程的上下文信息(如果当初调用者所在线程没有释放回线程池,上下文信息可以获取到)。 真正的async方法执行很快,线程还没释放回线程池。
结论:
引用大佬的结论,await之后的线程依据SynchronizationContext在不同环境中的不同定义而产生不同的结果。所以「await 之后不会开启新的线程(await 从来不会开启新的线程)」的肯定句式改成「await 之后会开启新的线程吗? Maybe」这样的句式更加合适些。