Hacker News new | ask | show | jobs
by throw827474737 1359 days ago
And why no just "classical" OS threads? Yeah, that's rhetoric, sure you can (or did you mean that with virtual one's?) And actually once upon a time, one of rust's selling point that you could do that safely without the common data races that you have to care for in the usual multithreading/multiprocessing environments, awesome!

So to your grandposter..:

> The point of async APIs is not speed boost, it's decoupling processing from the local call stack (which happens to hang up the GUI until the routine resolves, but also forces components to be tightly coupled and monolithic).

NO, just no! Async or similar approaches were motivated by super parallel concurrency (classic example is connection handling for a webserver) to have better performance vs the overhead you'd have with os thread primitives (and even there, nowadays, that is just a motivation that is not always true anymore..)

In no way is the point of "async style" decoupling.. that we can do on a lot of levels with a lot of primitives.. especially this is very unneeded for UIs where you can decouple UI from Cpu processing from everything else with usually (depends, sure) two to three permanent threads.

On top of that, async style is horrible also for our mental models.. most clear code happens with simple control flow, classical threads (no matter if green or os) shine there because they stick to that model much more than async.

Async style was and is still mostly for performance, definitely not for decoupling and also not for the nicer programming model..

But yeah, motivations and sense nowadays sadly often gets lost over hype :(

3 comments

> And why no just "classical" OS threads?

Because of memory footprint and thread contention.

OS thread's default stack size is often in the order of megabytes. On a server with 64GB of ram, that means you can't run more than ~64000 threads at once. That's not really a high number in the context of modern highly-concurrent servers.

Meanwhile, goroutine's (and probably green thread's and virtual thread's from languages other than Go) default stack size is in the order of kilobytes, allowing you to run millions of them concurrently.

Thread contention wastes CPU cycles on kernel-level context switches and may lead to hard-to-debug issues such as thread starvation. You generally have no control over how the OS scheduler manages OS threads, so without sophisticated thread synchronization mechanisms, you're relying on blind luck.

Userspace threads are usually scheduled by the language runtime itself, which gives it a higher level of control. For example, Go runtime schedules goroutine in a round-robin fashion, guaranteeing that all goroutines will have some kind of progress in a reasonable amount of time.

EDIT: Since this post is about UI, yeah, "classical" OS threads are pretty good choice, since you usually only need a single OS thread to handle all the UI events, while the rest of the system can do the processing. So both the "stack size" and "contention" arguments are not really relevant in that scenario.

> On a server with 64GB of ram, that means you can't run more than ~64000 threads at once. That's not really a high number in the context of modern highly-concurrent servers.

Obviously the OS does not allocate megabytes of actual physical RAM to thread stacks, it's just address space. Just, this:

https://unix.stackexchange.com/questions/127602/default-stac...

I wouldn't call it quite "obvious" (it certainly didn't cross my mind), but thanks for the information. Quite interesting.
> you can't run more than ~64000 threads

Please, we started here with a GUI framework and how someone said async is not about performance - in the end you underline my point? I said it was motivated by massively concurrent use cases that require a high number of threads... (and that similarly motivates green threads et al, full agree).

You asked a question, I answered it.

Moreover, the last paragraph of my post actually agrees with you.

There is absolutely no need for a confrontational attitude.

>NO, just no! Async or similar approaches were motivated by super parallel concurrency (classic example is connection handling for a webserver) to have better performance vs the overhead you'd have with os thread primitives (and even there, nowadays, that is just a motivation that is not always true anymore..)

No - that's completely wrong.

Event loops existed prior to them being popularised for IO scaling - they were used in GUI for way longer.

Async is just a way to transpose continuation based programming and the callback hell involved in dealing with event loops.

Writing UI code even in multithreaded code, without async, is a PITA because UI frameworks expect UI state to be updated on the UI thread - so you need to do work on thread X then schedule a callback on UI thread and update UI state. With async you just fire off a task, await with scheduler on the UI thread and you have linear code flow.

> Async style was and is still mostly for performance,

Scalability, not performance.

For a webserver, scalability (as in ability to handle a large number of concurrent request) is a performance metric. Speed of handling each one of those requests is another performance metric.