Skip to content
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

Group().imap on Queue deadlock #423

Closed
thinxer opened this issue Apr 4, 2014 · 5 comments
Closed

Group().imap on Queue deadlock #423

thinxer opened this issue Apr 4, 2014 · 5 comments

Comments

@thinxer
Copy link

thinxer commented Apr 4, 2014

# encoding: utf8

import gevent
from gevent.pool import Group
from gevent.queue import Queue


fetches = Queue()
validations = Queue()
results = Queue()

def searcher():
    fetches.put(True)
    validations.get()
    print "SEARCH DONE"
    fetches.put(StopIteration)


def validator():
    for result in Group().imap(lambda _:_, fetches):
        print "VALIDATION PUT"
        validations.put(True)
    print "VALIDATION DONE"
    validations.put(StopIteration)
    results.put(StopIteration)
    return


gevent.spawn(searcher)
gevent.spawn(validator)

results.get()

Output:

VALIDATION PUT
SEARCH DONE
Traceback (most recent call last):
  File "test.py", line 32, in <module>
    results.get()
  File "/Users/thinxer/Library/Python/2.7/lib/python/site-packages/gevent/queue.py", line 200, in get
    result = waiter.get()
  File "/Users/thinxer/Library/Python/2.7/lib/python/site-packages/gevent/hub.py", line 568, in get
    return self.hub.switch()
  File "/Users/thinxer/Library/Python/2.7/lib/python/site-packages/gevent/hub.py", line 331, in switch
    return greenlet.switch(self)
gevent.hub.LoopExit: This operation would block forever

It seems that imap never stopped, though fetches been put StopIteration.

Update:
Using Python 2.7 on Mac OS X Mavericks.
gevent.version is "1.0".

@thinxer
Copy link
Author

thinxer commented Apr 4, 2014

A Go version (using imap_unordered instead of imap): http://play.golang.org/p/TGKE5Kh1u0 , which works fine.

@thinxer
Copy link
Author

thinxer commented Apr 5, 2014

Will anyone tell me if this is intended, or a bug of gevent? Thanks in advance!

@fantix
Copy link
Contributor

fantix commented Apr 8, 2014

@thinxer This seems to be a bug in IMap:

    def _run(self):
        try:
            empty = True
            func = self.func
            for item in self.iterable:
                self.count += 1
                g = self.spawn(func, item)
                ....

    def _on_result(self, greenlet):
        self.count -= 1
        if greenlet.successful():
            self.queue.put((greenlet.index, greenlet.value))
        else:
            self.queue.put((greenlet.index, Failure(greenlet.exception)))
        if self.ready() and self.count <= 0:
            self.maxindex += 1
            self.queue.put((self.maxindex, Failure(StopIteration))) 

    def _on_finish(self, _self):
        if not self.successful():
            self.maxindex += 1
            self.queue.put((self.maxindex, Failure(self.exception)))

This piece of code assumes that _on_result is called after _run fully returns. But actually in your test code, self.iterable was fed with a gevent Queue object, which will switch to the hub when iterated, then no StopIteration would ever be fed to self.queue, because _on_result is called while iterating over self.iterable when the greenlet is not "ready" yet.

@thinxer
Copy link
Author

thinxer commented Apr 9, 2014

Yes it is. One of my coworkers pointed out the same issue. Checking self.count after the for loop in _run solves this bug. But I'm not sure if this change will make other things stop working.

@fantix
Copy link
Contributor

fantix commented Apr 9, 2014

@thinxer I think it should be okay - even replacing the current empty check is fine.

denik added a commit that referenced this issue Apr 11, 2014
It was possible for IMap/IMapUnordered greenlets to exit without putting the final StopIteration. So, whoever was waiting on the results would have to wait forever (or until LoopExit if there's nothing else running in the program).

Original patch and test by @thinxer.
denik added a commit that referenced this issue Apr 11, 2014
It was possible for IMap/IMapUnordered greenlets to exit without putting the final StopIteration. So, whoever was waiting on the results would have to wait forever (or until LoopExit if there's nothing else running in the program).

Original patch and test by @thinxer (close #424).

Fix #311: same issue.
denik added a commit that referenced this issue Apr 11, 2014
It was possible for IMap/IMapUnordered greenlets to exit without putting the final StopIteration. So, whoever was waiting on the results would have to wait forever (or until LoopExit if there's nothing else running in the program).

Original patch and test by @thinxer (close #424).

Fix #311: same issue.
@denik denik closed this as completed in e3ef3c8 Apr 11, 2014
denik added a commit that referenced this issue Apr 11, 2014
fix #423: pool: LoopExit in imap/imap_unordered
denik added a commit that referenced this issue Apr 29, 2014
It was possible for IMap/IMapUnordered greenlets to exit without putting the final StopIteration. So, whoever was waiting on the results would have to wait forever (or until LoopExit if there's nothing else running in the program).

Original patch and test by @thinxer (close #424).

Fix #311: same issue.
denik added a commit that referenced this issue Apr 29, 2014
It was possible for IMap/IMapUnordered greenlets to exit without putting the final StopIteration. So, whoever was waiting on the results would have to wait forever (or until LoopExit if there's nothing else running in the program).

Original patch and test by @thinxer (close #424).

Fix #311: same issue.
denik added a commit that referenced this issue Apr 29, 2014
It was possible for IMap/IMapUnordered greenlets to exit without putting the final StopIteration. So, whoever was waiting on the results would have to wait forever (or until LoopExit if there's nothing else running in the program).

Original patch and test by @thinxer (close #424).

Fix #311: same issue.
denik added a commit that referenced this issue Apr 29, 2014
It was possible for IMap/IMapUnordered greenlets to exit without putting the final StopIteration. So, whoever was waiting on the results would have to wait forever (or until LoopExit if there's nothing else running in the program).

Original patch and test by @thinxer (close #424).

Fix #311: same issue.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants