This is similar to Add Yield() function to python Threading, but now we’ve got some proper motivation for it.
When developing a multithreaded program, it’s sometimes desirable to explicitly release the GIL to let another thread execute (it’s probably useful for free-threading too, but I’m not going to focus on that). This is generally done with time.sleep(0)
, so something like:
def thread_2():
do_some_other_computing()
def thread_1():
do_some_computing()
time.sleep(0) # Explicitly give the GIL to thread 2, instead of relying on the switch interval
Recently, it was discovered that time.sleep(0)
is significantly slower on Unix systems–see this issue. As it turns out, fixing this has other negative implications (take a look at @picnixz’s PR), so this behavior will probably remain for the time-being.
Due to this issue, it’s sub-optimal to use time.sleep(0)
for yielding the GIL, at least on non-Windows systems. The suggested alternative is to use os.sched_yield
, but that doesn’t exist on Windows! Solutions using os.sched_yield
will need an additional code path that falls back to time.sleep(0)
if they want to support Windows.
So, this isn’t overall great. I propose adding a new function to threading
(let’s call it yield_thread
) that does this independent of the platform, which will both:
- Shed some light on the problem with
time.sleep(0)
, so people stop using it for scheduling. - Provide a seamless drop-in for
time.sleep(0)
(unlikeos.sched_yield
).
Using the example from before, it would be very similar in usage:
def thread_2():
do_some_other_computing()
def thread_1():
do_some_computing()
threading.yield_thread()
FWIW, there’s some precedent in other languages for this, but I’m not particularly sure it matters:
- Java’s Thread.yield()
- C++11’s std::this_thread::yield
- Rust’s thread::yield_now
- JavaScript’s scheduler.yield()