-
Notifications
You must be signed in to change notification settings - Fork 45
Limit for number of Tasks running in sequence? #43
Comments
Turns out This Is A Very Hard Problem :'>
More recent Fantasy Land specs have introduced a separate algebra, ChainRec, which kind of stands for a "tail-recursive monad" of sorts. A new The one way to mitigate the problem you're seeing is to wrap all of your tasks in some asynchronous operation, so they start in an empty stack. Something like this would work: const unstack = (task) => task.chain(v => {
return new Task((reject, resolve) => {
setTimeout(() => resolve(v));
}, (timer) => clearTimeout(timer));
});
monads.sequence(Task, R.map(unstack, R.map(Task.of, 1)))
.fork(...); This, however, adds a fair amount of overhead between each Task. Instead of just having one task start another (and maybe have the VM optimise that), each Task schedules its continuation and yields back to the main thread. With You could group a limited amount of tasks together and move them to a clean stack (with the unstack function) as a group, but that's unreliable since you can't know how much stack space you still have left when Fluture implements ChainRec if the overhead of starting on an empty stack is too much for your codebase. I'm not familiar with its design choices and performance characteristics though. |
Not just that. Almost all operations in Fluture are stack safe. ChainRec is really just there for interoperability. Just try to run the exact same code given above but using Fluture: const R = require('ramda');
const Future = require('fluture');
const monads = require('control.monads');
const COUNT = 1000000; //I increased the number a little to make sure
const l = R.repeat(1, COUNT);
monads.sequence(Future,
R.map(Future.of, l))
.fork((err) => console.error(err),
(res) => console.log(res)); On my i5 machine, after 2.8 seconds, we see: [1,
1,
1,
...,
1,
1,
... 999900 more items] This all happened in the same tick we called |
@Avaq does Fluture use free monads or something similar to build the nested computations and run them later using a constant amount of stack space? |
@robotlolita It doesn't use free monads directly, but the same principal. Every operation just builds up a structure (much resembling an AST) and
The second trick is the flattening of newly encountered AST's. When we call a |
@robotlolita @Avaq : tnx a lot for the explanation of root cause and the pointers to additional info. I'll take a look at Fluture. By the way, is the implementation of ChainRec in the plans for folktale 2.0? |
nvm. found it in the backlog. tnx |
The number of Tasks that can be run in sequence seems to be limited by the max size of the function stack for the platform. Sample code:
will produce:
The text was updated successfully, but these errors were encountered: