Coroutines are a control-flow primitive which allows for a lot of useful things, including advancing program state while a coroutine waits on a syscall, generators, iterators, producer-consumer patterns with channels, and combinations of these things. They generalize function calls, or structure goto, if you prefer.
Some of these applications are glossed as concurrent, particularly their use to free the thread when execution blocks, but all of them are single-threaded. Goroutines are preëmptively scheduled, and can be relocated between threads transparently. That isn't really a coroutine, which is why they have a different name.
The README has some notes on how to use Neco coroutines in a multithreaded environment. It's basically how you'd run execution paths of multiple function calls on several threads, because coroutines are an orthogonal concern to threads.
Handling multiple threads to access multiple CPUs would make it far more complex. And frankly a single thread is plenty for handling, say, a chat server.
I feel the word "coroutine" is slowly losing its original meaning, similar to what happened to "lambda".
Also don't get me wrong, meaning of words do change, I am grumpy about it but that's fine. Kinda feel weird to have people telling me it has always meant that.
These are stackful, symmetric coroutines with a build-in scheduler. It implements suspend and resume. You can call that a green thread if you want, or a fiber or whatever. They're coroutines.
The API docs make all of this clearer than the README. https://github.com/tidwall/neco/blob/main/docs/API.md
So a coroutine is basically something you can explicitly yield control flow from or give control flow to. neco doesn't really let you do that. Caller of neco_resume isn't relinquishing the control flow to another coroutine. neco_yield looks like a coroutine yield, but for asymmetric coroutine it should yield to caller, for symmetric coroutine it should let you specify who you are yielding to. This one does neither.
And I feel if you stretch the definition of coroutine to include this, then you can basically call most multitasking systems coroutines, rendering the concept mostly useless.
Although, deep in our hearts we all must know that lambda was already taken, it is an eigenvalue.
Stackful coroutines create a new stack for each coroutine thread and save and restore the appropriate registers when switching. Stackless coroutines are basically normal C functions that have been hacked to save their local variables between calls and use gotos (or, notoriously, a switch statement) to resume from where they last yielded. Both are very useful in their own way.
This is a great project and I'll be trying it out in my current work.
BTW, here is my macros for stackless coroutine in C: https://github.com/liuliu/co/blob/master/example.c
Stackful coroutines are more flexible in that they don't have the calling limitations since they have their own stack. The big downside is that they are much more complex to implement and use (understand). The code has to create and destroy stacks from scratch and switch contexts by saving and restoring the correct registers (so your platform has to be supported explicit). This may cause compatibility problems with some code. Those activities also require more resources, but still not very much. For some people they will be easier to use since you don't have to roll anything yourself.
> neco_chan *messages = argv[0];
neco_chan → neko chan → kitty cat (in japanese)... coincidence? ^_^Any notes about why I would try Neco in the future?
It's nice to have multiple options. For instance the interface can be very different.
> Webassembly: Must be compiled with Emscripten using the -sASYNCIFY flag.
while (1) {
neco_sleep(NECO_SECOND*2);
printf("tock\n");
}Either this is a library you might use, so you should obviously review the code before you include it in your own work, or this is something that intrigued you, so you'll find clever ideas by digging into its implementation.
Here, neco_sleep eventually calls a function that tells the coroutine scheduler to pause the current (calling) and resume the next eligible coroutine in its collection.
I was going to actually implement an echo server for load balancer health checks with minimal memory usage, but never considered doing it in C but I might just use it! Thank you so much.