4 ms·
Context switching will happen regardless of where your thread implementation lives. Reimplementing scheduling in a bespoke fashion in usermode will not give you
by otabdeveloper4 3y ago
Context switching will happen regardless of where your thread implementation lives. Reimplementing scheduling in a bespoke fashion in usermode will not give you the gains that you hope for.
Basically, learn how an OS works first before trying to reimplement it badly.
- flohofwoe 3y agoI guess the idea is that an async/await context switch would always be cheaper than an OS thread context switch. Whether that is actually true probably depends a lot on the specific operating system and async/await runtime (I think there's a lot of mysticism involved seeing async/await as some sort of silver bullet instead of relying on cold hard performance numbers alone).
- otabdeveloper4 3y agoThere's no reason to believe it should be cheaper. The contents of the context and the process of switching it is the same regardless of where in the software stack you're doing it. (Async/await was invented in interpreted languages to circumvent their global interpreter locks, which is a whole different problem not related to context switching at all.)
- ReactiveJelly 3y agoThat's now how I heard it. Event loops were old hat in GUIs, and web servers like Nginx adopted them so they could service thousands of requests concurrently without allocating stack space for thousands of threads. And the context is not the same. Switching threads requires you to go through the kernel scheduler, so it has to change page tables and stuff in the CPU, right? It lets you write simpler code too, because some events can be handled in the loop without involving mutexes and thread safety. If async/await is, as you claim, a pointless hack for interpreted languages, why did Nginx, written in C, get so much traction with essentially the same architecture?
- yazaddaruvala 3y agoI’m not sure where you’ve gotten this information but I would recommend you do some more research. There is a lot of great info about operating systems - specifically ring0 vs ring1 for the context switch overhead. Meanwhile, only Python and Ruby had GILs. Async/await became popular through JavaScript and C#. Now very popular in Rust as well. None of these runtimes have a GIL. Async/await or Fibers (C++, Go, Java 21) are entirely about context switching overhead.
- vitus 3y ago> Async/await became popular through JavaScript and C#. Now very popular in Rust as well. None of these runtimes have a GIL. To be fair, while typical JS implementations do not have a GIL, it's usually unnecessary due to the runtime being single-threaded. In case anyone else is curious when the above languages grew this feature: (F# piloted this in the 1.x days, back in 2009 or earlier.) It seems like C# developed this feature first in 5.0 in 2012, followed by JS (Dec 2016 in Chrome, widely supported across other major browsers within a few months). Python 3.7 came out in 2018, Ruby 3.0 came out in 2020. Async/await landed in C++20 via coroutines, and Java 21 landed last month. Rust grew this feature in 2018, which landed in the stable channel in 1.39 (Nov 2019). Golang has had goroutines / channels since day 1.
- dragonwriter 3y ago> To be fair, while typical JS implementations do not have a GIL, it's usually unnecessary due to the runtime being single-threaded. Yeah, "we avoid a GIL because we don't offer threads at all" is, like pre-1.9 Ruby's, "we don't have a GIL because are threads are 1:N green threads" both technically "no GIL" but also worse for thread-based parallelism, then "we have native threads, but there is a GIL, which native code can release". > Ruby 3.0 came out in 2020. Ruby 3.0 doesn't have async/await, though. There's a third-party colorless Async gem, and built in constructs (that require a scheduler implementation) for lower-friction asynchronous programming (async as an approach has been popular for Ruby for quite a while), but not with async/await syntax in either case.
- 3y ago
- gpderetta 3y agoThere are two primary costs to preemptive, kernel-driven context switch: first is the userspace to kernelspace transition cost which, while has been going down for a while, it is still non-trivial and actual got worse with the various spectre mitigations. Second cost is that preemptive context switches must by by necessity conservative and need to save and restore a lot of state that might not be necessary on a cooperative switch. Stackless (i.e. async/await as opposed to green threads or stackfull coroutines) context switches have the additional advantage that they reuse most of the stack and only suspend a single stack frame. This means that the rest of the call stack (shared between contextes) can stay hot in cache. Whether any of these costs matter depend a lot on the application, the amount of context switches and the amount of work done between switches.