Fibers/Coroutines #585
Replies: 4 comments
-
Hi. Not sure what you mean, please provide more details. |
Beta Was this translation helpful? Give feedback.
-
I will try to elobrate function process_task(options){
if (options.inrush){
long_running_code2();
} else {
long_running_code();
}
}
function long_running_code(){
//generate 1MB RSA keys using javascript
}
function long_running_code2(){
var wakeup=(v)=>result=v;runtime.resume();
go_provided_rsa(wakeup);
var result;
runtime.yield();
return result;
//generate 1MB RSA key using golang on another goroutine
} Let say we want to use our runtime for many concurrent tasks at a time, goja is not coroutine safe, so we must delegate all calls into the runtime to one specific go routine. There are 3 solutions to this problem, promise, generator, and fiber, with promise and generator I will need to change the signatures of all intermediate functions to async, as well as the go function will need to return a promise, and the call to the top function will return a promise that needs special handling in go. I was thinking that goja has already the infrastructure to do it, but got lost in the code while trying to implement it. With fibers, the vm.Execute call will return immediatly signaling that the return is not ready because the callstack has yielded, and the go_provided_rsa function will have the job of reactivatng that call stack, by calling the wakeup function, we will need to have some task ID to be able to retrive the return later, or we could make a vm.ExecuteTask that will return a channel of T any to be resolved when the top callstack finally reaches its end. refs |
Beta Was this translation helpful? Give feedback.
-
I see. It's an interesting approach but it has an impact on the external (i.e. Go-facing) API. It means that every code evaluation, including calls to exported functions can return a special "to be continued" result which needs to be handled. It's very similar to making every function implicitly asynchronous. As much as I'm not keen on having two-coloured functions, the community has decided to go that way and I don't think it would make sense trying to support the both approaches. Certainly I don't have any resources to do so. |
Beta Was this translation helpful? Give feedback.
-
I see. In the mean time I tried to study and understand the VM, and I might have another idea, to have this benefit. In LISP this is working like this call_cc(function(_continue){
do_some_async_work_with_callback(_continue);
}); Whenever the evaluator/stepper will encounter a call to the call/cc function, it will call the function, and pass an anoynimus function with a wakeup parameter, stop to loop (stay at this call continuation) and let the function body decide when to continue. Another benefit of this approach is the option to save the _continue somewhere global, and use it as a half baked procedure, and finalize it multiple times with other prameters. With that approach maybe it is simpler, we could do it internally in the vm.go file (I am asking because I am not sure, maybe I will try it out myself).
I am not sure whether the async code will be able to run while the VM is paused, I havn't manged to find how sub functions are executed (PC jump, or new VM). We will not have the secnd lisp benefit I mentioned above, because once we continue we lose the current state, unless we pass the VM to call_cc parameters, but this may be overwhelming. All the best |
Beta Was this translation helpful? Give feedback.
-
Goja supports already async/yield and pausing the VM.
Fibers would be an additinal way how a callstack could be retianed, but with the addition of giving to Go the right to continue the execution of that task, in addition to the benefits of allowing to incrementely make code async without the need of having the whole call stack aware (as opposed to async/yield).
Is this already possible with Goja? I've attempted and failed many times to implement it.
Beta Was this translation helpful? Give feedback.
All reactions