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

difference between Asynchronous and Synchronous in .net 4.5

在我阅读 .Net 4.5 中的异步编程时 asyncawait 关键字 我阅读了Here下面的段落

Processing Asynchronous Requests

In web applications that sees a large number of concurrent requests at start-up or has a bursty load (where concurrency increases suddenly), making these web service calls asynchronous will increase the responsiveness of your application. An asynchronous request takes the same amount of time to process as a synchronous request. For example, if a request makes a web service call that requires two seconds to complete, the request takes two seconds whether it is performed synchronously or asynchronously. However, during an asynchronous call, a thread is not blocked from responding to other requests while it waits for the first request to complete. Therefore, asynchronous requests prevent request queuing and thread pool growth when there are many concurrent requests that invoke long-running operations.

对于粗体字,我无法理解为什么异步请求与同步请求需要相同的时间来处理?

例如:

public async Task MyMethod()
{
    Task<int> 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<int> LongRunningOperation() // assume we return an int from this long running operation 
{
    await Task.Delay(1000); //1 seconds delay
    return 1;
}

我的理解是 LongRunningOperation() 从第一行开始执行,这里调用 Task<int> longRunningTask = LongRunningOperation(); 和 returns 调用 await 后的值, 所以从我的角度来看,异步代码比同步代码快,对吗?

另一个问题:

据我了解,正在执行 MyMethod() 的主线程并未阻塞等待 LongRunningOperation() 完成,但它 returns 进入线程池以服务于另一个请求。那么是否有另一个线程分配给 LongRunningOperation(); 来执行它?

如果是那么异步编程和多线程编程有什么区别?

更新:

假设代码变成这样:

public async Task MyMethod()
    {
        Task<int> 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<int> LongRunningOperation() // assume we return an int from this long running operation 
    {
        DoSomeWorkNeedsExecution();
        await Task.Delay(1000); //1 seconds delay
        return 1;
    }

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

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

现在,如果您启动一个任务并且不等待它立即完成,您可以使用同一个线程来做一些其他工作,但它不会 "speed up" 异步操作的 运行:

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

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

因此,当 运行ning MyMethod 的线程到达 await longRunningTask 时,它会被释放(只要 longRunningTask 尚未完成)。如果它是一个 ThreadPool 线程,它将 return 到 ThreadPool,它可以在您的应用程序中处理一些其他代码。


关于更新流程是这样的:

  • MyMethod 开始处理
  • LongRunningOperation 开始处理
  • DoSomeWorkNeedsExecution 在调用线程上执行
  • LongRunningOperation 中达到了 await,因此 return 编辑了一个热门任务。
  • DoIndependentWork由同一个调用线程执行(LongRunningOperation仍然是"running",不需要线程)
  • MyMethod 中达到 await。如果原始任务完成,同一个线程将同步继续,否则,将 return 编辑一个热任务,最终完成。

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

考虑两者的区别:

Thread.Sleep(1000);

await Task.Delay(1000);

两者都需要一秒钟才能到达 运行。然而,在前一种情况下,当前线程将被阻塞(并且其所有资源都无用),而在后一种情况下,当前线程可以做其他有用的事情(例如,服务于另一个请求)。

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

回复。 另一个问题

释放的线程将用于其他事情;在操作完成之前不会分配线程。这是可能的,因为底层 OS 本身是异步的。在上面的示例中,使用了一个计时器,它会在线程空闲时发出信号让线程启动,而不是线程因内部停止而停止。

(基于 I3arnon 的回答)

同步操作和使用 async-await 的操作总的来说花费相同的时间并不完全正确。

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

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

问题中的引述与网络应用程序有关。对于 Web 应用程序,异步操作更多的是在可接受的时间内为最大数量的请求提供服务,而不是为每个请求节省几微秒。另一方面,如果涉及上下文切换,最终会花费更多时间,这就是为什么在 Web 应用程序中使用 Task.Run 对应用程序弊大于利。

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