Putting a thread to sleep until event X occurs
Solution 1
What you're looking for is known as a condition variable.
Here is the Python 2 library reference.
For Python 3 it can be found here
Solution 2
Looks like you want a threading.Semaphore associated with each handler (other synchronization objects like Events and Conditions are also possible, but a Semaphore seems simplest for your needs). (Specifically, use a BoundedSemaphore: for your use case, that will raise an exception immediately for programming errors that erroneously release the semaphone more times than they acquire it -- and that's exactly the reason for being of the bounded version of semaphones;-).
Initialize each semaphore to a value of 1
when you build it (so that means the handler is available). Each using-thread calls acquire
on the semaphore to get the handler (that may block it), and release
on it when it's done with the handler (that will unblock exactly one of the waiting threads). That's simpler than the acquire/wait/notify/release lifecycle of a Condition, and more future-proof too, since as the docs for Condition say:
The current implementation wakes up exactly one thread, if any are waiting. However, it’s not safe to rely on this behavior. A future, optimized implementation may occasionally wake up more than one thread.
while with a Semaphore you're playing it safe (the semantics whereof are safe to rely on: if a semaphore is initialized to N, there are at all times between 0 and N-1 [[included]] threads that have successfully acquired the semaphore and not yet released it).
Related videos on Youtube
Comments
-
tipu almost 2 years
I'm writing to many files in a threaded app and I'm creating one handler per file. I have HandlerFactory class that manages the distribution of these handlers. What I'd like to do is that
thread A requests and gets foo.txt's file handle from the HandlerFactory class
thread B requests foo.txt's file handler
handler class recognizes that this file handle has been checked out
handler class puts thread A to sleep
thread B closes file handle using a wrapper method from HandlerFactory
HandlerFactory notifies sleeping threads
thread B wakes and successfully gets foo.txt's file handle
This is what I have so far,
def get_handler(self, file_path, type): self.lock.acquire() if file_path not in self.handlers: self.handlers[file_path] = open(file_path, type) elif not self.handlers[file_path].closed: time.sleep(1) self.lock.release() return self.handlers[file_path][type]
I believe this covers the sleeping and handler retrieval successfully, but I am unsure how to wake up all threads, or even better wake up a specific thread.
-
Mark Amery almost 9 yearsThe GIL does not significantly degrade I/O performance, only processing performance (see wiki.python.org/moin/GlobalInterpreterLock). Since the OP seems to be using threads to parallelise I/O, your assertion that he is losing most of the benefits of multi-threading is unwarranted.
-
Ami almost 9 yearsI suggest you look at page 38 of the referenced PDF file at dabeaz.com/python/GIL.pdf. Even with 1 CPU the GIL degrades response time of I/O bound threads on a multi-core system (and sometimes on a single-core system), if you are using multiple python threads, due to the overhead of checking the GIL.