c #async运行单线程?

时间:2013-07-18 21:39:39

标签: c# async-await c#-5.0

我正在阅读http://msdn.microsoft.com/en-US/library/vstudio/hh191443.aspx。 示例代码:

async Task<int> AccessTheWebAsync()
{ 
    // You need to add a reference to System.Net.Http to declare client.
    HttpClient client = new HttpClient();

    // GetStringAsync returns a Task<string>. That means that when you await the 
    // task you'll get a string (urlContents).
    Task<string> getStringTask = client.GetStringAsync("http://msdn.microsoft.com");

    // You can do work here that doesn't rely on the string from GetStringAsync.
    DoIndependentWork();

    // The await operator suspends AccessTheWebAsync. 
    //  - AccessTheWebAsync can't continue until getStringTask is complete. 
    //  - Meanwhile, control returns to the caller of AccessTheWebAsync. 
    //  - Control resumes here when getStringTask is complete.  
    //  - The await operator then retrieves the string result from getStringTask. 
    string urlContents = await getStringTask;

    // The return statement specifies an integer result. 
    // Any methods that are awaiting AccessTheWebAsync retrieve the length value. 
    return urlContents.Length;
}

该页面还说:

  

async和await关键字不会导致创建其他线程。异步方法不需要多线程,因为异步方法不能在自己的线程上运行

这是否“没有创建其他线程”是否适用于标记为async?

的方法的范围

我想,为了让GetStringAsync和AccessTheWebAsync同时运行(否则GetStringAsync将永远不会像AccessTheWebAsync现在拥有的那样完成),最终GetStringAsync必须在AccessTheWebAsync线程的不同线程上运行。

对我来说,编写异步方法只有在没有添加更多线程时才有用,因为它等待的方法也是异步的(已经使用额外的线程来并行执行它自己的事情)

我的理解是否正确?

4 个答案:

答案 0 :(得分:13)

这是async力量的关键。 GetStringAsync和其他自然异步操作不需要线程GetStringAsync只发送HTTP请求并注册回调以在服务器回复时运行。只需等待服务器响应就不需要线程。

实际上,线程池只使用了一小部分。在上面的示例中,GetStringAsync注册的回调将在线程池线程上执行,但它只是通知AccessTheWebAsync它可以继续执行。

我有async intro blog post你可能会觉得有帮助。

答案 1 :(得分:2)

  

我想,为了让GetStringAsync和AccessTheWebAsync 同时运行 ......

它们不会同时运行(至少不是你想的那样)。现在,如果HttpClient.GetStringAsync本身

  • 开始在不同的线程上工作,然后该代码可以同时运行,-or -
  • 如果等待(使用ConfigureAwait(false)),那么该方法中的其余工作将被调度到线程池线程(以便代码可以同时运行。

关键是将方法声明为async和/或使用await,不会导致您创作的方法在单独的线程上运行(您必须这样做)明确地说。)

注意: 如果没有其他异步方法的代码(或文档),您实际上并不知道它有多少是同步运行的。在该方法执行await或显式启动另一个线程(通常是通过启动新的Task

之前,它才真正开始异步

答案 2 :(得分:0)

如果有必要,可以从线程池中获取一个线程来进行操作。在控制台(不讨论UI线程或IO线程)的情况下,当前线程进入控制台并且执行另一个线程,并且该新线程是执行剩余操作的线程。

答案 3 :(得分:-3)

作者在这里说的是,在某处简单地使用async和await关键字不会导致当前方法在不同的线程上运行。我们来调查一下提供的代码会发生什么。

async Task<int> AccessTheWebAsync()
{ 
    // You need to add a reference to System.Net.Http to declare client.
    HttpClient client = new HttpClient();

    // GetStringAsync returns a Task<string>. That means that when you await the 
    // task you'll get a string (urlContents).
    Task<string> getStringTask = client.GetStringAsync("http://msdn.microsoft.com");

到目前为止,所有事情都在一个线程中执行。此时,client.GetStringAsync调用可以剥离一个新线程(虽然这不是任何异步方法的保证)。应该注意的是,GetStringAsync方法基本上是在当前线程上启动的(例如实际进行调用),但是一旦返回,读取响应将在不同的线程中执行。这由它返回一个Task对象来表示。任务可以表示已经完成的工作,当前正在执行的辅助线程,或者只是安排稍后执行的工作单元。

DoIndependentWork();

现在,在呼叫排队(或可能已发送)后,我们的主线程上会执​​行此操作。因此,这可能在等待返回请求时发生。请注意,我们仍然是我们的主要线程。

 string urlContents = await getStringTask;

此时,我们的线程返回。 .NET将创建一个包含方法其余部分的延续函数(return urlContents.Length;),一旦getStringTask在它自己的线程上完成,它将自动为我们调用。此时,新线程将获取延续。

通过所有这些,我们在async方法中编写的全部内容,直到await关键字,都在一个线程中运行。当然,我们调用了另一种可能会产生另一个线程的方法,但是我们没有采取任何措施来仅使用async / await关键字来创建另一个线程。最后的延续可能由不同的线程调用,但是在我们的初始函数实际返回之后(这就是为什么我们的函数返回一个Task对象,表示当对该函数的任何调用返回时可能尚未完成的工作)