laverdet / node-fibers

Fiber/coroutine support for v8 and node.
MIT License
3.56k stars 224 forks source link

Can you use generators with Fibers? #430

Closed tcf909 closed 4 years ago

tcf909 commented 4 years ago

@laverdet Any issues with using Fibers with generators and yield that you know of? I know with await there is an issue getting back into a Fiber after awaiting. Anything similar you've run across with generators and yield?

I've tested a bunch of scenarios and everything seems fine, but I have a big implementation to do based on generators and wanted to double check with you before I get too far down the path.

Thanks

laverdet commented 4 years ago

I would imagine yield would behave identically to await in this case.

tcf909 commented 4 years ago

Early testing showed otherwise...which is why I was confused.

I'll post some working examples, but basically upon returning from a yield a Fiber was still available via Fiber.current

laverdet commented 4 years ago

It depends on if the original stack has unwound. await will always run on a clean stack but yield might not.

tcf909 commented 4 years ago

It seems to maintain the original stack -- very interesting. Wonder if there is risk of this breaking in the future. Thoughts?

Test code:

const Sync = require('@digitalspaces/syncho');
Sync(() => {
    function* test(v){
        while(true){
            Sync.wait(cb => setTimeout(cb, 100));
            yield v;
            Sync.wait(cb => setTimeout(cb, 100));
            if( ! require('fibers').current )
                throw new Error();
            console.log(new Error());
/* Output--------------->
  Error
    at test (/Users/tc.ferguson/Sync/Workspace/MyDigitalSpaces/benchmarks/test2.js:26:16)
    at test.next (<anonymous>)
    at /Users/tc.ferguson/Sync/Workspace/MyDigitalSpaces/benchmarks/test2.js:33:13
*/
        }
    }
    for( const v of test()){
        console;
    }
});
laverdet commented 4 years ago

I recommend trying without fibers to get a better sense of how generators work.

function* gen() {
    for (;;) {
        console.trace();
        yield;
    }
}

const foo = gen();
foo.next();
process.nextTick(() => foo.next());

Logs:

Trace
    at gen (/Users/marcel/a.js:3:11)
    at gen.next (<anonymous>)
    at Object.<anonymous> (/Users/marcel/a.js:9:5)
    at Module._compile (internal/modules/cjs/loader.js:959:30)
    at Object.Module._extensions..js (internal/modules/cjs/loader.js:995:10)
    at Module.load (internal/modules/cjs/loader.js:815:32)
    at Function.Module._load (internal/modules/cjs/loader.js:727:14)
    at Function.Module.runMain (internal/modules/cjs/loader.js:1047:10)
    at internal/main/run_main_module.js:17:11
Trace
    at gen (/Users/marcel/a.js:3:11)
    at gen.next (<anonymous>)
    at /Users/marcel/a.js:10:28
    at processTicksAndRejections (internal/process/task_queues.js:75:11)

If you unwind from a fiber you won't be in a fiber anymore.