Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Stop a thread: flag vs. Event [duplicate]

I saw examples e.g. here of using an Event to stop a thread where I think a boolean flag would do the job.

 Event

class MyThread(threading.Thread):

    def __init__(self):
        self._please_stop = threading.Event()

    def run(self):
        while not self._please_stop.is_set():
        [...]

    def stop(self):
        self._please_stop.set()

 Flag

class MyThread(threading.Thread):

    def __init__(self):
        self._please_stop = False

    def run(self):
        while not self._please_stop:
        [...]

    def stop(self):
        self._please_stop = True

What is the benefit of using an Event, here? Its wait method is not used. What makes it better than a boolean flag?

I can see the point if the same Event is shared among several threads, but otherwise, I don't get it.

This mailing list thread suggests that Event would be safer, but it's unclear to me why.

More precisely, I don't understand those two paragraphs:

If I understand the GIL correctly, it synchronizes all access to Python data structures (such as my boolean 'terminated' flag). If that is the case, why bother using threading.Event for this purpose?

The GIL is an implementation detail and relying on it to synchronize things for you isn't futureproof. You're likely to have lots of warning, but using threading.Event() isn't any harder, and it's more correct and safer in the long term.

I agree that using an Event adds close to no overhead, so I can stick to that, but I'd like to understand the limits of the flag approach.

(I'm using Python3, so I'm not concerned by Python2 limitations, if any, although those would be totally worth mentioning here.)

like image 554
Jérôme Avatar asked May 09 '17 20:05

Jérôme


Video Answer


2 Answers

Programming is often not just about getting the code to work today, it's about keeping it working through changes that will be made in the future.

  • Other Python implementations don't have the GIL. Will I want to run it on pypy tomorrow?
  • Actually, I need to spread the work across several processes. Swap in multiprocessing... which implements Event() but will fail if you're just using a local variable.
  • Turns out the code should stop only if several other threads think it should. Well, use Semaphore() instead of Event()... but would be easy to implement incorrectly with variables.

So, it's likely you can write multithreaded programs perfectly correctly in Python relying on how the bytecode gets interrupted and when the GIL can be released... but if I am reading and changing your code later, I'd be much happier if you used the standard synchronization primitives.

like image 80
gz. Avatar answered Sep 28 '22 16:09

gz.


I think that the implication in the thread you quote is that setting a boolean is not necessarily an atomic operation in Python. While having a global lock on all Python objects (the GIL) makes all operations that set an attribute appear atomic for the moment, such a lock may not exist in the future. Using Event makes the operation atomic because it uses its own lock for access.

The link for atomic is to a Java question, but it is no less relevant because of that.

like image 44
Mad Physicist Avatar answered Sep 28 '22 16:09

Mad Physicist