6 ms·
There have been library implementations of this for years. And they are a far cry from true lwt aka golang.
by tus88 7y ago
There have been library implementations of this for years. And they are a far cry from true lwt aka golang.
- anonymoushn 7y agoGoroutines are not copyable so they're not really a substitute for byuu/co
- tomcam 7y agoI think my mind is about to be blown. What does copyable mean when it comes to coroutines?
- anonymoushn 7y agoA description of one thing you can do with this is at https://github.com/moonjit/moonjit/issues/84 https://github.com/moonjit/moonjit/issues/84 It's not a common feature. Usually it's present in a language that has "continuations" and the api is something dreadful like call/cc. But you can use it in Lua with the above mentioned patch, and you can use it in byuu/co with memcpy.
- simias 7y agoI object to the use of "dreadful" for call/cc, it's just a different paradigm that requires a different way of thinking but it's not a bad thing per-se. It's not like goto or setjmp which are fundamentally unsound constructs that completely break the flow of the program.
- anonymoushn 7y agoWhen designing these primitives, I think there are a few considerations: When creating a new execution context, which one should begin executing, and which one should be bound to a local variable in the executing one? Should there be any primitive that switches to an already-existing execution context without creating a copy of it? How many primitives should there be? call/cc answers: "The new execution context should begin executing and the old one should be bound to a local variable, no, one" As a person who occasionally explains these things to people who have never been exposed to them, I strongly prefer: "The old execution context should continue executing and the new one should be bound to a local variable, yes, as many as we need to produce the preceding answers" I think without trying too hard you can get the number of primitives in the latter case down to three, "create", "copy", and "switch." If you wanted to bug your users you could get it down to two.
- wbl 7y agoCall/cc is not very composeable.
- tsimionescu 7y agoWell, call/cc usually makes it impossible to add a construct like 'finally' to a language, so it does at least block some options.
- anonymoushn 7y agoDepending on what you want from this, you can maybe use dynamic-wind. But yeah.
- tus88 7y agoLol continuations will blow your mind. "Returning" to somewhere else than you came? Humbug!
- rakoo 7y agoUnless I'm mistaken you can already do that with go's channels
- tus88 7y agoHint: I don't mean returning data ;-)
- rakoo 7y agoAnd you don't need to return data with channels, even though you typically do. They are primarily a tool for controlling flow with concurrent goroutines. Do you have an example of what you have in mind so we can see more clearly what it is about?
- anonymoushn 7y agobyuu's comment in this comment tree gives a good example.
- byuu 7y agoSerialization [1]. Say you want to take a snapshot of where your program is, run the code some more, and then later on restore execution back to that snapshot. In the parlance of video games and emulators, this would mean save states. You could use these save states to implement speculative execution to eg remove input latency from games using a method called run-ahead [2]. With state machines, this is trivial: just record all the state machine variables. With coroutines / cooperative threading, it's not: the state is all stored on the stack frame. My stackful coroutine library can do this by essentially memcpy'ing the stack frames themselves, but it comes with some seriously negative caveats: the biggest is you can't save this to disk, because on the next program run, ASLR, etc would invalidate the pointers in the stack frame. In fact, you can't even safely release and allocate new memory between a serialize and unserialize point, or the stack frames may have dangling pointers in them. In practice, this is acceptable and workable for features like real-time rewind and run-ahead. Library support for C++ coroutine serialization would be trivial since they are stackless. Getting around the limitations I mentioned for stackful coroutines would be immensely more challenging. [1] https://byuu.net/design/cooperative-serialization https://byuu.net/design/cooperative-serialization [2] https://byuu.net/input/run-ahead https://byuu.net/input/run-ahead
- speedplane 7y ago> Getting around the limitations I mentioned for stackful coroutines would be immensely more challenging. Challenging but it's definitely been done before. The system below [1] (disclosure: I worked on it years ago), stores every memory write in a separate buffer on the assembly level. You need to modify the compiler for this, and it cuts performance roughly in half, but it allows you to step backwards in code and perform sophisticated performance analysis. [1] https://www.ghs.com/products/timemachine.html https://www.ghs.com/products/timemachine.html
- byuu 7y agoOh certainly, it's just beyond what I can do as a C library. I've also seen another approach that implemented a customized libc replacement to allow this to work. But that and modifying the compiler itself are really extreme steps. It's still doable, and it's definitely worth doing, but I understand the uses I've mentioned are rather niche, so it's unlikely to occur. For one, we still don't have built-in stackful coroutine support even in C++20.
- gumby 7y agoIn c++20 lambdas are now copyable and there’s no reason the routines calling co_awai, co_yield, and co_return can’t be lambdas perhaps called by lookup.
- halayli 7y agoIs that so? Please elaborate
- tus88 7y agohttps://en.m.wikipedia.org/wiki/GNU_Portable_Threads https://en.m.wikipedia.org/wiki/GNU_Portable_Threads N:M threading from 1999! And there are many more recent examples too.
- armitron 7y agoIt's not N:M with arbitrary M, but N:1 (mentioned in the link you posted). There is no parallelism whatsoever in GNU Pth. You only get a single kernel thread and "green" userland threads cooperatively scheduled on top of that single kernel thread. That's it.
- civicsquid 7y agoIt looks like Facebook's `folly` library had an implementation of coroutines available in their experimental directory since mid-2018. There was still some evolution going on after it was pushed though (and it seems like there still is today). Not sure if that helps the argument that this has been around for "years" (since it's still in the experimental directory), but I guess there were some libraries trying to accomplish this. https://github.com/facebook/folly/tree/master/folly/experimental/coro https://github.com/facebook/folly/tree/master/folly/experime...
- pjmlp 7y agoThe only implementation that I would consider around of years, were the C++/CX extensions, and even those aren't 100% like ISO C++ ones ended up looking like, although Microsoft was a big contributor to its design.
- pjmlp 7y agoGo routines are a tiny subset of what coroutines allow in other languages, because Go doesn't have the concept of generators/continuations nor exposes the low level runtime management APIs.
- gpderetta 7y agoTechnically goroutines are equivalent to one shot continuations, while generators, lacking the ability to capture a call stack are not (they capture the return continuation, but not any arbitrary one). So no, go coroutines (or any stack full coroutines) are actually more powerful than thise exposed in other languages.
- AnanasAttack 7y agoC++ coroutines are stackless