2013-07-18 39 views
6

我在读http://msdn.microsoft.com/en-US/library/vstudio/hh191443.aspx。 示例代码:c#异步运行单线程?

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; 
} 

该页面还表示:

异步和等待关键字不会导致创建额外的线程。异步方法不需要多线程,因为异步方法不会在其自己的线程上运行

是否在标记为异步的方法范围内应用此“没有附加线程”?

我会想象为了GetStringAsync和AccessTheWebAsync同时运行(否则GetStringAsync将永远不会完成,因为AccessTheWebAsync现在有控制权),最终GetStringAsync必须从AccessTheWebAsync的线程运行在不同的线程上。

对我来说,写异步方法在不增加时,它等待的方法也更异步线程(已使用额外的线程做自己的事并行)

我的理解是否正确才是有用的?

回答

12

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

实际上,线程池只用了一点点。在上例中,由GetStringAsync注册的回调将在线程池线程上执行,但它所做的只是通知AccessTheWebAsync它可以继续执行。

我有一个async intro blog post你可能会发现有帮助。

+0

你能解释一下“自然异步操作不需要线程”是什么意思吗?如何处理这项工作?你在谈论单个线程在任务中分配的时间吗? –

+1

@VincePanuccio:在评论中描述有点长,但我有[博客文章](http://blog.stephencleary.com/2013/11/there-is-no-thread.html)详情。 –

1

我会想象为了既GetStringAsync和AccessTheWebAsync 同时在运行...

他们没有在同一时间的方式运行(至少不你在想)。现在,如果HttpClient.GetStringAsync本身

  • 开始在不同的线程的工作,那么该代码可以在同一时间运行, - 或 -
  • 有一个的await(与ConfigureAwait(假)),则该方法中的工作的其余部分将在该线程池中的线程调度(让这些代码可以在同一时间和/或使用await声明的方法为async运行。

点,不会导致您正在编写的方法在单独的线程上运行(您将不得不这样做itly)。

注意: 如果没有另一种异步方法的代码(或文档),您并不知道它有多少是同步运行的。它并没有真正启动是异步的,直到方法做一个await或明确地在另一个线程开始工作(通常是通过启动新Task

-3

什么笔者在这里说,是,简单地使用异步和等待某个关键字不会导致当前的方法在不同的线程上运行。让我们来看看在提供的代码中会发生什么。

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完成它自己的线程,它将自动被调用。那时,一个新的线程将会继续。

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

+1

这个答案是完全错误的。 “任务”对象不一定代表代码;特别是'GetStringAsync'永远不会启动另一个线程来等待服务器。 –

0

如果需要,还有一个线程从线程池中取得。在控制台的情况下(不讨论UI线程或IO线程),当前线程进入控制台,另一个线程用于执行,而这个新线程是执行剩余操作的线程。