yossi
yossi

Reputation: 13315

Using gevent monkey patching with threading makes thread work serially

I am using gevent and I am monkey patching everything.
It seems like the monkey patching causes the threading to work serially.

My code:

import threading
from gevent import monkey; monkey.patch_all()

class ExampleThread(threading.Thread):
    def run(self):
        do_stuff()  # takes a few minutes to finish
        print 'finished working'

if __name__ == '__main__':
    worker = ExampleThread()
    worker.start()
    print 'this should be printed before the worker finished'

So the thread is not working as expected.
But if I remove the monkey.patch_all() it is working fine.
The problem is that I need the monkey.patch_all() for using gevent (now shown in the code above)

My solution:

I changed the

monkey.patch_all() 

to

monkey.patch_all(thread=False)

so I am not patching the thread.

Upvotes: 27

Views: 30646

Answers (2)

Bob
Bob

Reputation: 6173

You can leave your Thread-based class in place if you substitute the Thread with Greenlet, for example like this:

from gevent import monkey
from gevent import Greenlet
from threading import Thread


class ThreadLikeGreenlet(Greenlet):
    def __init__(self, name=None, target=None, args=(), kwargs=()):
        super().__init__(target, *args, **dict(kwargs))
        self.name = name

def is_gevent_patched():
    return monkey.is_module_patched('threading')

if is_gevent_patched():
    Thread = ThreadLikeGreenlet  # substitute Thread with Greenlet

class ExampleThread(Thread):
    ...

it will work as you wish then.

Upvotes: 0

jcollado
jcollado

Reputation: 40414

When threads are monkey patched in gevent, they behave as coroutines. This means that you have to explicitly yield control to make it possible for other coroutines to execute.

The way to do this is call a blocking operation that has been patched (this will yield automatically) or gevent.sleep:

#!/usr/bin/env python
from gevent import monkey, sleep
monkey.patch_all()
import threading

class ExampleThread(threading.Thread):
    def run(self):
        for i in xrange(10):
            print 'working'
            sleep()

if __name__ == '__main__':
    worker = ExampleThread()
    worker.start()
    print 'this will be printed after the first call to sleep'

Upvotes: 35

Related Questions