.net 4.5中的异步和同步之间的区别

在我阅读.Net 4.5 async异步编程和await关键字时,我在这里阅读以下段落

处理异步请求

在启动时看到大量并发请求或具有突发性负载(并发性突然增加)的Web应用程序中,使这些Web服务调用异步将提高应用程序的响应能力。 异步请求与同步请求相同的处理时间。 例如,如果请求进行需要两秒钟完成的Web服务调用,则无论是同步执行还是异步执行,请求都需要两秒钟 。 但是,在异步调用期间,在等待第一个请求完成时,不阻止线程响应其他请求。 因此,当有许多并发请求调用长时间运行的操作时,异步请求会阻止请求排队和线程池增长。

对于粗体字,我无法理解它们异步请求如何处理同步请求需要相同的时间?

例如:

 public async Task MyMethod() { Task longRunningTask = LongRunningOperation(); //indeed you can do independent to the int result work here //and now we call await on the task int result = await longRunningTask; //use the result Console.WriteLine(result); } public async Task LongRunningOperation() // assume we return an int from this long running operation { await Task.Delay(1000); //1 seconds delay return 1; } 

我的理解LongRunningOperation()从第一行开始执行调用此处Task longRunningTask = LongRunningOperation(); 并且一旦调用await返回值,所以从我的角度来看异步代码比同步更快,是吗?

另一个问题:

据我所知,执行MyMethod()的主线程没有阻塞等待LongRunningOperation()完成,但它返回到线程池以提供另一个请求。 那么是否有另一个线程分配给LongRunningOperation(); 执行它?

如果是,那么异步编程和multithreading编程之间有什么区别?

更新:

让我们说代码变成这样:

 public async Task MyMethod() { Task longRunningTask = LongRunningOperation(); //indeed you can do independent to the int result work here DoIndependentWork(); //and now we call await on the task int result = await longRunningTask; //use the result Console.WriteLine(result); } public async Task LongRunningOperation() // assume we return an int from this long running operation { DoSomeWorkNeedsExecution(); await Task.Delay(1000); //1 seconds delay return 1; } 

在这种情况下,在DoIndependentWork()执行期间, LongRunningOperation()会由另一个线程执行?

异步操作并不快。 如果异步等待10秒(即await Task.Delay(10000) )或同步(即Thread.Sleep(10000),它将花费相同的10秒 。 唯一的区别是第一个不会在等待时保持一个线程,但第二个将会

现在,如果您启动任务并且不等待它立即完成,您可以使用相同的线程来执行其他工作,但它不会“加速”异步操作的运行:

 var task = Task.Delay(10000); // processing await task; // will complete only after 10 seconds 

关于你的第二个问题: Task.Delay (像其他真正的异步操作一样)不需要执行一个线程,因此没有线程 。 Task.Delay是使用你启动的System.Threading.Timer实现的,当它完成时会引发一个事件,同时它不需要一个线程,因为没有代码可以执行。

因此,当运行MyMethod的线程到达await longRunningTask它被释放(只要longRunningTask还没有完成)。 如果它是一个ThreadPool线程,它将返回到ThreadPool ,它可以处理应用程序中的其他代码。


关于更新,流程将如此:

  • MyMethod开始处理
  • LongRunningOperation开始处理
  • DoSomeWorkNeedsExecution在调用线程上执行
  • LongRunningOperation达到LongRunningOperation ,因此返回一个热门任务。
  • DoIndependentWork由同一个调用线程执行( LongRunningOperation仍在“运行”,不需要线程)
  • MyMethod达成了await 。 如果原始任务完成同一个线程将同步进行,如果没有,则返回最终完成的热任务。

因此,您使用async-await的事实允许您使用一个线程,否则该线程会被阻塞,同步执行CPU密集型工作。

考虑之间的区别:

 Thread.Sleep(1000); 

 await Task.Delay(1000); 

两者都需要一秒钟才能运行。 但是在前一种情况下,当前线程将被阻塞(并且其所有资源都无用),而在后一种情况下,当前线程可以执行其他有用的操作(例如,提供另一个请求)。

异步性不是关于加速单个指令序列,而是能够在同步代码阻塞时执行操作。

回覆。 另一个问题

释放的线程将用于其他事情; 在操作完成之前不会分配线程。 这是可能的,因为底层操作系统本身是异步的。 在上面的示例中,使用了一个计时器,当线程空闲时,该计时器会通知线程,而不是为内部停止的线程。

(以I3arnon的答案为基础)

使用async-await同步操作和操作总体上需要花费相同的时间,这并不是绝对正确的。

async-await有一些额外的逻辑。 检查已完成的等待者和状态机。 这使得一些异步操作比相应的同步操作花费更多时间。

另一方面,适合async-await大多数操作自然是异步的,并且还需要一些额外的处理来使其外观和感觉同步。 在这些情况下,异步操作比同步操作花费的时间更少。

问题的引用与Web应用程序有关。 对于Web应用程序,异步操作更多的是在可接受的时间内提供最大数量的请求,而不是保存每个请求的几微秒。 另一方面,如果涉及上下文切换,则最终需要花费更多时间,这就是为什么在Web应用程序中使用Task.Run对应用程序来说效果更糟糕的原因。

如果您想了解有关async-awit更多信息,请阅读我的async-awit curation上的文章。