3 ms·
There'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 s
by otabdeveloper4 3y ago
There'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.
- vitus 3y ago> 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. (I haven't written anything in Ruby in roughly a decade, so I'm happy to defer to anyone who's actually followed the language the whole time) That's fair. I had skimmed and found some reference to the async gem relying on Fiber::SchedulerInterface which was introduced in 3.0, although it apparently existed back in 2017. There's similarly the async-await gem by the same org (also first released in 2017), which at least partially supports that syntax. But in either case, it's not a native language feature.
- otabdeveloper4 3y agoYou should take your own advice, because have no clue what a context switch even is. P.S. C++ async is entirely about running on embedded hardware, not about "overhead". P.P.S. All garbage-collected languages have a GIL of some sort. This is the real reason GC languages aren't used in systems programming, not GC pauses.
- 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.