12

.NET async/await in a single picture

 4 years ago
source link: https://tooslowexception.com/net-asyncawait-in-a-single-picture/
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.
neoserver,ios ssh client

.NET async/await in a single picture

It is said that picture is worth a thousand words, and I agree. That’s why I like preparing technical drawings to explain various concepts. So, here it is – a short story of how async/await works in .NET.

thereisnothread

The main power behind async/await is that while we “await” on an ongoing I/O operation, the calling thread may be released for doing other work. And this provides a great thread re-usability. Thus, better scalability – much smaller number of threads is able to handle the same amount of operations comparing to asynchronous/waiting approach.

The main role here plays so-called overlapped I/O (in case of Windows) which allows to asynchronously delegate the I/O operation to the operating system, and only after completion the provided callback will notify us about the result. The main workforce here is so-called I/O completion port (IOCP).

I/O completion ports are a very efficient mechanisms for asynchronous I/O in Windows, allowing to observe huge amount of ongoing operations by only one port. So indeed, in case of .NET all this is baked by only a single IOCP. Then, a few I/O completion threads (managed by a ThreadPool) are observing this single IOCP. Typical number of IOCP threads is about equal to number of logical processors, but ThreadPool may create up to 1000 by default (we can change this maximum).

The callback of I/O operation is executed on one of the IOCP threads – it sets the result of the operation and decides whether to:

  • execute continuation in-place on the IOCP thread itself – which is beneficial because it does not incur any more context switches and avoids cache trashing, but obviously has the risk of polluting (an important) IOCP thread with the user code (which may lead to threads starvation).
  • or schedule it back to “the other place” – which may be pointed by SynchronizationContext/TaskScheduler, so quite typically it will be just queued for execution by worker threads

Typically most continuations are scheduled to the worker threads. One of the most significant exceptions are HttpClient continuations on Windows (since .NET Core 2.1).

Note. In case of Linux epoll mechanism is used instead of IOCPs. There is/are epoll thread(s), listening to events, that schedule the continuation to the worker threads (no inlining may happen). And ongoing work to rebuild ThreadPool for Linux using AIO and io_uring is being made.

All the dots are connected by a state machine instance, keeping track of the status, continuation to execute, the whole context ans so on.

Drawing this reminded me famous “There is no thread” article from Stephen Cleary where he explains that there are no “user code executing” threads consumed when an asynchronous I/O operations is performed. And indeed it is true, although as people also noticed in the comments, there are IOCP threads blocked for processing I/O completion port notifications – so, there is (almost) no thread.

Similar picture about more generic relationship between ThreadPool and I/O completion port drawn pretty big attention yesterday, so you may be also interested:

.NET ThreadPool and an overlapped I/O – this will be heavily reused in explaining async/await too pic.twitter.com/kaC2FTxbkI

— Konrad Kokosa (@konradkokosa) May 25, 2020

All this is just a work for a much bigger project, which is https://asyncexpert.com/ on-line course about asynchronous and concurrent programming in .NET. If you found it interesting, stay tuned by subscribing to the newsletter on the above-mentioned page!


Recommend

  • 126
    • 微信 mp.weixin.qq.com 7 years ago
    • Cache

    浅谈Async/Await

    在很长一段时间里面,FE们不得不依靠回调来处理异步代码。使用回调的结果是,代码变得很纠结,不便于理解与维护,值得庆幸的是Promise带来了.then(),让代码变得井然有序,便于管理。于是我们大量使用,代替了原来的回调方式。但是不存在一种方法可以让当前的执行流...

  • 76
    • beckjin.com 7 years ago
    • Cache

    ASP.NET 谨用 async/await

    ASP.NET 谨用 async/await

  • 75

    C# 5.0 引入 async/await 关键字,旨在简化异步编程模型,抛去语法糖就是 Net4.0 的 Task + 状态机。其实在处理异步编程使用 Task 还是挺简单的,不过既然推出了新的语法糖,难免会尝试一下,然而在使用中却没想象中那么单纯。以下针对ASP.NET 应用程序实际使用过...

  • 81
    • start.jcolemorrison.com 7 years ago
    • Cache

    5 Tips and Thoughts on Async / Await Functions

    So I finally hopped on the boat with usa...

  • 44
    • www.tuicool.com 6 years ago
    • Cache

    Async and Await in Rust: a full proposal

    I’m really excited to announce the culmination of much of our work over the last four months: a pair of RFCs for supporting async & await notation in Rust. This will be very impactful for Rust in the network services...

  • 70

    Node.js express.js MongoDB JWT REST API - Basic Project Skeleton Getting started This is a basic API REST skeleton written on JavaScript using async/await. Great for building an MVP for your front-en...

  • 56
    • manjusaka.itscoder.com 6 years ago
    • Cache

    去 async/await 之路

    看到彭总写的文章 这破 Python ,感慨颇多,我也来灌水吧。 首先,我司算是在国内比较敢于尝试新东西的公司吧,最直接的提现就在于我们会及时跟进社区相关基础服务的迭代...

  • 11

    The danger of async/await and .Result in one picture Sync over async in .NET is always b...

  • 6
    • tooslowexception.com 4 years ago
    • Cache

    .NET debugging in a single picture

    .NET debugging in a single picture – TooSlowException Performance, architecture, Software Craftmanship... Diagnostic expert!...

  • 10

    Async / Await vs. PipeTo in Akka.NET Actors Best Practices and Patterns for Asynchronous Programming with Akka.NET Actors Many years ago I wrote...

About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK