-
Notifications
You must be signed in to change notification settings - Fork 151
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
FiberIterator not passing iterator to block, "call 'next' on nil" exception #148
Comments
Ah, yes.. I don't think I ever got to inject, hence the commented out spec: I'd start with getting a failed spec, and then we can iterate from there! |
Got it. I'll investigate a version of inject that will play nicely against that spec... But I'm having some difficulty with the spec as defined. We're going to add the numbers 1 to 5 in order, two fibers at a time. Each of the two fibers will start with the current tally, add their number, and call return on the iterator with the sum, updating the tally. Only one of the fibers will win this race condition, unless we introduce sequencing within return. I expect to see something like:
If I modify FiberIterator.each to not auto-advance and run the spec as given, this is indeed the result. To take this from another perspective, if I introduce some persistent object that's carried through the process and accessible to all fibers, I get a natural ordering of updates. For example, here's the same spec with a hash instead of an integer:
And the output is as expected:
I'm interested to know what you think and in which direction you think I should proceed. It seems like its not possible to carry the semantics of inject over to this concurrent world without requiring the use of some tricks to avoid race conditions. Now, I'm very new to this world of fibers and Eventmachine so I could be wrong. If I seem so certain, forgive me. I'm really not. :) |
Humm.. yeah, this is a tricky one: require 'eventmachine'
EM.run do
EM::Iterator.new((1..5), 2).inject(0, proc{ |total,num,iter|
EM.next_tick {
p [total, num]
total += num
iter.return(total)
}
}, proc{ |results|
p results
EM.stop
})
end
EM.run do
total = []
EM::Iterator.new((1..5), 2).inject(total, proc{ |total,num,iter|
EM.next_tick {
p [total, num]
total.push num
iter.return(total)
}
}, proc{ |results|
p results.inject(:+)
EM.stop
})
end Yields
So the behavior is consistent with EM's iterator implementation. I'm not really sure there is a clean solution here.. @tmm1 any suggestions? |
Very interesting. I'll probably go with a map-reduce style implementation, as you give in your second example. Thanks! |
We still need to fix the .next bug, but other then that.. Probably worth checking-in the spec + some docs on the gotcha's of using it between multiple fibers. :) |
any new love to be spread here? :) |
I'm using a FiberIterator to iterate over a list of redis clients, collecting the hashes that are returned by injection —
For the iteration, each works great. However, interation using inject produces the following exception:
It seems that FiberIterator's each method is not passing an interator into the foreach/blk proc. The implementation of inject in Eventmachine expects a non-nil iterator on which it can call next.
If I knew what the intended behavior was supposed to be, I would have submitted a patch. A temporary, ulgy and wrong fix is the following code:
The text was updated successfully, but these errors were encountered: