async-await threading internals

mbu*_*nik 22 .net c# asynchronous async-await

我很好奇异步等待线程内部.

每个人都声明async在性能方面要好得多,因为它释放了等待长异步调用响应的线程.好的我明白了.

但让我们考虑一下这种情况.

我有一个异步方法在数据库上执行异步操作.数据库的api公开函数BeginQuery和事件QueryCompleted.我用任务包装了那些(使用TaskCompletionSource).

我的问题是调用BeginQuery和触发事件QueryCompleted之间的内幕.

我的意思是 - 它不需要产生某种工人来解雇事件吗?在非常低的级别,它必须是一些阻止来自db的线程读取结果的同步循环.

我认为任何异步调用都必须生成一个线程来实际处理响应(可能在驱动程序代码中的低级c ++循环中等待它).

所以我们唯一的"收获"是当一些其他线程正在执行其工作时,可以释放调用者线程.

调用异步方法总是创建一个新的工作线程吗?

有人可以证实我的理解吗?

Ste*_*ary 36

每个人都声明async在性能方面要好得多,因为它释放了等待长异步调用响应的线程.

是的,不是.重点async是释放调用线程.在UI应用程序中,async响应性的主要好处是,因为UI线程被释放.在服务器应用程序中,主要的好处async是可伸缩性,因为请求线程被释放以处理其他请求.

所以我们唯一的"收获"是当一些其他线程正在执行其工作时,可以释放调用者线程.始终调用异步方法是否正在创建新的工作线程?

在操作系统级别,所有I/O都是异步的.在底层异步I/O正在进行时,它是阻塞线程的同步API.我最近在博客文章中写道:没有线程.


vto*_*ola 6

我的意思是 - 它不需要产生某种工人来解雇事件吗?在非常低的级别,它必须是一些阻止来自db的线程读取结果的同步循环.

它将创建一个IO完成端口(IOCP),表示正在外部处理的任务,该线程将继续执行其他操作.然后,当IOCP通知任务完成时,线程将获取IOCP的状态并继续执行任务.

http://www.drdobbs.com/cpp/multithreaded-asynchronous-io-io-comple/201202921

I/O完成端口为编写使用多线程和异步I/O的可伸缩服务器应用程序的问题提供了一个优雅的解决方案.


nos*_*tio 5

我的意思是 - 不需要产生某种工人来触发事件吗?在非常低的级别,它必须是某个同步循环阻塞了从 db 读取结果的线程。

即使您实际上必须等待内核对象(例如手动重置事件),您仍然可以将阻塞的同步代码转换为异步代码并将线程从阻塞中释放出来(更新:真实场景)。

例如,同步代码:

void Consume()
{
    var completedMre = new ManualResetEvent(false);

    producer.StartOperation(completedMre);

    completedMre.WaitOne(); // blocking wait

    Console.WriteLine(producer.DequeueResult());
}
Run Code Online (Sandbox Code Playgroud)

异步模拟:

async Task ConsumeAsync()
{
    var completedMre = new ManualResetEvent(false);

    producer.StartOperation(completedMre);

    var tcs = new TaskCompletionSource<Result>();

    ThreadPool.RegisterWaitForSingleObject(completedMre, 
        (s, t) => tcs.SetResult(producer.DequeueResult()),
        null, Timeout.Infinite, true);

    var result = await tcs.Task;
    Console.WriteLine(result);
}
Run Code Online (Sandbox Code Playgroud)

异步版本最多可扩展 64 倍(MAXIMUM_WAIT_OBJECTS,这是可以聚合RegisterWaitForSingleObject以等待单个线程的内核对象的最大数量)。因此,您可以Consume()并行调用64 次,它将阻塞 64 个线程。或者你可以调用ConsumeAsync64 次,它只会阻塞一个线程。