class Program
{
static void Main(string[] args)
{
var rst = DownloadPage("http://www.baidu.com");
//var rst2=GetString();
Console.ReadKey();
}
private static async Task<string> DownloadPage(string url)
{
using (var client = new HttpClient())
{
PringMsgWithThreadId("Before await");
var response = await client.GetAsync(url).ConfigureAwait(continueOnCapturedContext:false);
var content= await response.Content.ReadAsStringAsync();
PringMsgWithThreadId(content.Substring(0, 10));
PringMsgWithThreadId("After await");
return content;
}
}
private static async Task<string> GetString()
{
PringMsgWithThreadId("Before await");
var result = await GetStringAsync();
PringMsgWithThreadId(result);
PringMsgWithThreadId("After await");
return result;
}
private static Task<string> GetStringAsync()
{
var task = new Task<string>(() =>
{
Thread.Sleep(1000 * 2);
return "string after sleep two seconds";
});
task.RunSynchronously();
return task;
}
private static void PringMsgWithThreadId(string tag)
{
Console.WriteLine($"{tag}(ThreadId:{Thread.CurrentThread.ManagedThreadId})");
}
}
运行时输出DownloadPage()方法输出:
运行GetString()方法时输出
我的问题:
1.当调用DownloadPage()时,为什么在主线程(ThreadId:10)以外的线程(ThreadID:15)中执行await之后的代码。
2.当调用GetString()时,为什么在同一个线程中执行await之后的代码(两个threadId都是10)。
答案 0 :(得分:8)
await
从不创建新主题。
正如我async
intro所解释的,await
将首先检查其论点(任务)。如果已经完成,则继续同步执行。否则,它会暂停&#34;该方法并使用其参数注册回调(即,在任务上放置一个延续)。
稍后,当任务完成时,将继续运行。由于您在没有SynchronizationContext
/ TaskScheduler
的控制台应用中,该延续将在线程池线程上运行。
所以,你的第一个问题的答案是主线程忙(在Console.ReadKey
中被阻止),并且控制台应用中的主线程也不是线程池线程。第二个问题的答案是因为GetStringAsync
中的任务是同步运行并且在它返回时已经完成,这会导致await
GetString
继续(同步)。
另一方面,您永远不应该使用任务构造函数。如果要返回已完成的任务,请使用Task.FromResult
。如果要在后台线程上执行某些工作,请使用Task.Run
。