为什么等待有时会创建新线程,但有时不会?

时间:2017-04-09 10:16:26

标签: c# multithreading asynchronous async-await

    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()方法输出:

enter image description here

运行GetString()方法时输出

enter image description here

我的问题:

1.当调用DownloadPage()时,为什么在主线程(ThreadId:10)以外的线程(ThreadID:15)中执行await之后的代码。

2.当调用GetString()时,为什么在同一个线程中执行await之后的代码(两个threadId都是10)。

1 个答案:

答案 0 :(得分:8)

await 从不创建新主题。

正如我async intro所解释的,await将首先检查其论点(任务)。如果已经完成,则继续同步执行。否则,它会暂停&#34;该方法并使用其参数注册回调(即,在任务上放置一个延续)。

稍后,当任务完成时,将继续运行。由于您在没有SynchronizationContext / TaskScheduler的控制台应用中,该延续将在线程池线程上运行。

所以,你的第一个问题的答案是主线程忙(在Console.ReadKey中被阻止),并且控制台应用中的主线程也不是线程池线程。第二个问题的答案是因为GetStringAsync中的任务是同步运行并且在它返回时已经完成,这会导致await GetString继续(同步)。

另一方面,您永远不应该使用任务构造函数。如果要返回已完成的任务,请使用Task.FromResult。如果要在后台线程上执行某些工作,请使用Task.Run

相关问题