Live data from Hacker News

Ruby methods are colorless

jpcamara.com

41–50 of 242 posts

Re: Ruby methods are colorless

#41
post #15

I've implemented coroutines in C and C++; my preferred multitasking environment is message-passing between processes. I'm not quite sure what the async/await stuff is buying us (I'm thinking C++, here). Like, I get multi-shot stackless coroutines, i.e., function objects, but I don't get why you'd want to orchestrate some sort of temporal Turing pit of async functions bleeding across your code base. I dunno. Maybe I'm…

I think the async/await patterns solve one problem really well: UI latency.

My UI background is web testing and C++ game UIs in C++. There are like 3 patterns in multithreaded games. Thread per responsibility (old/bad), Barriers blocking all threads and give each game system all the threads, or something smart. Few games do something smart, and the thread per responsibility is not ideal and we will ignore it for now.

In games often pausing everything and letting the physics system have all the threads for a few milliseconds is "fast enough". Then the graphics systems will try to use all the threads, and so on so that eventually everything will get all the threads even thought everything else rarely needs it. Sometimes two things are both close to single threaded and have no data contention so they might both be given threads, but this is almost always a manually decided things by experts.

This means that once UI, the buttons, the text, cursors, status bars, etc, gets its turn there won't be any race conditions (good), but if it needs to request something from disk that pause will happen on a thread in the UI system (bad and analogous to web sites making web API calls) so UI latency can be a real problem. If any IO small or some resource system has preloaded it then there isn't a detectable slowdown, but there are still plenty of silly periods of waiting. There is also a lot of time when some single threaded part of the game isn't using N-1 hardware threads and all that IO could have been asynchronous. But often game UIs are a frame behind the rest of the game simulation and there is often detectable latency in the UI like the mouse feeling like it drags or similar.

Allowing IO to run in the back while active events are processed can reduce latency and this is the default in web browsers. IO latency in web pages is worse than in games and other computation seems smaller than games, so the the event loop is close to ideal. A function is waiting? throw it on the stack and grab something else to do! This means that all the work that can be done while waiting on IO is done and when does well makes a UI snappy.

If that were available sensibly in games it could allow a game designed appropriately to span IO across multiple frames and be snappy without stutters. With games using the strategy I described above latency in the game simulation or IO can cause the UI to feel sluggish and vice versa. In games caching UI details and trying to pump the frame rate is "good enough". If the UI is a frame behind but we have 200 frames per second, that isn't really a problem. But when it chugs and the mouse stops responding because the player built the whole game world out of dynamite and set it off the game will not process the mouse until that 30 minutes of physics work is done.

There are better scheduling schemes for games. I am a big fan of doing "something smart" but that usually means scheduling heterogenous work with nuanced dependencies and I have written libraries just for that because it isn't actually that hard. But if you don't have the raw compute demands of a game scheduling IO along side your UI computation is often "fast enough" and is any easy enough mental model for JS devs to grok and allow them freedom to speed things up with their own solutions like caching schemes and reworking their UIs.

Re: Ruby methods are colorless

#42
post #15

I've implemented coroutines in C and C++; my preferred multitasking environment is message-passing between processes. I'm not quite sure what the async/await stuff is buying us (I'm thinking C++, here). Like, I get multi-shot stackless coroutines, i.e., function objects, but I don't get why you'd want to orchestrate some sort of temporal Turing pit of async functions bleeding across your code base. I dunno. Maybe I'm…

I work on a large multi-threaded ruby code base and it's always a pain to deal with engineers introducing the async usage in it. Most of the time these engineers don't have a grasp on what fibers are good for and we have to painstakingly review their code and provide feedback that no, it's not magical concurrency, we have a limited number of fix sized connection pools for postgres, redis, memcache, etc available in the process and fibers have to respect those limits as much as threaded code. In fact it's better if you don't introduce any additional concurrency below the thread-per-request model if you can. Only in places like concurrent http calls do we allow some async/fiber usage but even then it ends up nominally looking like threaded code and the VM context switching time saved by using fibers instead of threads is trivial. Trying to use fibers instead of threads in typical CRUD workloads feels a little cargo culty to me.

Fibers are cool and performant but usually they should be limited to lightweight work with large concurrency requirements.

Re: Ruby methods are colorless

#43

>Because threads share the same memory space they have to be carefully coordinated to safely manage state. Ruby threads cannot run CPU-bound Ruby code in parallel, but they can parallelize for blocking operations Ugh. I know Ruby (which I used to code in a lot more) has made some real progress toward enabling practical use of parallelism but this sounds still pretty awful. Is there any effort to make sharing data acr…

That's what Ractor is for, if you want full parallelization without processes.

And, yes, it's to do with a GIL/GVL. The lock is released during blocking IO, and some C extensions etc., so in practice for a lot of uses it's fine.

Re: Ruby methods are colorless

#44
post #34

I feel like I have some intuative understanding of how go achieves colorless concurrency using "go routines" that can park sync/blocking io on a thread "as needed" built into the runtime from the very begining. I don't understand how Ruby added this after the fact, globally to ALL potential cpu/io blocking libraries/functions without somehow expressing `value = await coro` Python is currently going through an "colori…

> I don't understand how Ruby added this after the fact, globally to ALL potential cpu/io blocking libraries/functions without somehow expressing `value = await coro`

In Python gevent can monkeypatch the standard library to do that transparently (mostly). I assume it works the same way except better: have the runtime keep track of the current execution (mostly the stack and ip), when reaching a blocking point register a completion event agains the OS then tell the fiber scheduler to switch off, the fiber scheduler puts away all the running state (stack and instruction pointer) then restores an other one (hopefully one that's ready for execution) and resumes that.

Re: Ruby methods are colorless

#45
post #34

I feel like I have some intuative understanding of how go achieves colorless concurrency using "go routines" that can park sync/blocking io on a thread "as needed" built into the runtime from the very begining. I don't understand how Ruby added this after the fact, globally to ALL potential cpu/io blocking libraries/functions without somehow expressing `value = await coro` Python is currently going through an "colori…

Java has shown that a sufficiently strong runtime can take the burden onto itself long after the facts have been established. Python in contrast has a runtime ultimately held back by its deep integration with the C-ecosystem which creates more black-boxes inside the runtime than you can find inside a swiss cheese. Similar with C# and Rust. No strong runtime, no colorless functions for you.

> Similar with C# and Rust. No strong runtime, no colorless functions for you.

Zig is the exception here but not sure how well it worked out in practice.

Re: Ruby methods are colorless

#46
post #15

I've implemented coroutines in C and C++; my preferred multitasking environment is message-passing between processes. I'm not quite sure what the async/await stuff is buying us (I'm thinking C++, here). Like, I get multi-shot stackless coroutines, i.e., function objects, but I don't get why you'd want to orchestrate some sort of temporal Turing pit of async functions bleeding across your code base. I dunno. Maybe I'm…

Ever done any UI programming or other paradigms where you have a specific OS thread used for cross runtime synchronization but you need to efficiently call background threads knowing exactly what's running where?

Async/await handles that well and so far the other paradigms just have not targeted these use cases well.

Message passing and promise libraries end up looking a lot like async/await with less sugar. (Compared to C#'s async/await implementation. The level of sugar depends on the language, of course.)

Re: Ruby methods are colorless

#47
post #36

I'm confused, and please correct me if I'm wrong. Aren't all these calls blocking? Doesn't `File.read` still block? Sure it's multithreaded, but it still blocks. Threading vs an event loop are two different concurrency models.

> Aren't all these calls blocking?

Only locally, which is pretty much the same as when you `await` a call.

> Threading vs an event loop are two different concurrency models.

The point is that you can build a "threading" (blocking) model on top of an event loop, such that you get a more natural coding style with most of the gain in concurrency.

It loses some, because you only have concurrency between tasks (~threads) leaving aside builtins which might get special cased, but my observation has been that the vast majority of developers don't grok or want to use generalised sub-task concurrency anyway, and are quite confused when that's being done.

For instance in my Javascript experience the average developer just `awaits` things as they get them, the use of concurrent composition (e.g. Promise.all) is an exception which you might get into as an optimisation, e.g. `await`-ing in the middle of a loop is embarrassingly common even when the iterations have no dependency.

Re: Ruby methods are colorless

#48
post #15

I've implemented coroutines in C and C++; my preferred multitasking environment is message-passing between processes. I'm not quite sure what the async/await stuff is buying us (I'm thinking C++, here). Like, I get multi-shot stackless coroutines, i.e., function objects, but I don't get why you'd want to orchestrate some sort of temporal Turing pit of async functions bleeding across your code base. I dunno. Maybe I'm…

In our C++ stack at work we accept HTTP requests, and then spawn internal IO which takes some time. During that time, we yield the handler thread to handle other requests. The arrival of the internal response sets up the next step in the request handler to resume, which needs the response message.

This can be done manually by polling status of descriptors, and stepping into and out of callables / passed continuations by hand, or it can be done with a task scheduling API and typesafe chained async functions.

Pick your poison, I guess, but it probably scales better than using synchronous IO and thread-per-request.

Re: Ruby methods are colorless

#49
> 3. You can only call a red function from within a red function

The base of most arguments against async. And it's false. You can call red from blue. And you should, sometimes.

Re: Ruby methods are colorless

#50

>Because threads share the same memory space they have to be carefully coordinated to safely manage state. Ruby threads cannot run CPU-bound Ruby code in parallel, but they can parallelize for blocking operations Ugh. I know Ruby (which I used to code in a lot more) has made some real progress toward enabling practical use of parallelism but this sounds still pretty awful. Is there any effort to make sharing data acr…

They ditched the GIL a while a ago. But there are smaller locks fighting for resources.

EDIT - I remember when patch notes years ago said the GIL was gone and this says there is a GVL, I guess there is some subtle difference.

then I think for practical purposes, "yes" is your answer, but not in precisely that name.

Post reply on HN