Doofah
Doofah

Reputation: 424

The print method and GIL

I have a multi-threading program and have faced an interesting phenomenon recently.

If I call the print method in the worker of a thread, the program turns very reactive. There's no big trick, just calling the print method resolves everything.

I have recently read an article about Python's Global Interpreter Lock aka GIL and it was saying the GIL is released once an I/O bound stuff is executed. Do you think the print call is also an I/O bound?

I would really like to make my program reactive but it is obviously awkward to dump data on the stdout while it's running. So I tried to redirect the output to /dev/null but it didn't resolve the issue:

with contextlib.redirect_stdout(None):
    print('')

I would appreciate if you have an idea so that I can reproduce the same effect with the following call but without dumping anything:

print('')

As far as I see the phenomenon, the GIL is released while the interpreter is working for print(''). Maybe I need such a short break which releases me from the GIL.

This is just for your information but I have tried to call the following method:

print('', end='', flush=True)

Of course, it didn't dump anything but my program turned a bit jaggy and it looked to be the thread had occupied the execution time so other threads were running very infrequently.

Update

If I call usleep(1) of QThread expecting to let it sleep for 1 us, then it waits much more than I specified. For example. the thread worker runs every 1 ms which is very slow because I was expecting to run it in the microsecond order. Calling print('') makes the thread running in a few microseconds order. In this meaning, I call it reactive.

Update

I feel something is drugging the execution time of the thread but it's not usleep or time.sleep(). However, I've faced a fact that print can kick the blocker away. So I would like to know what is actually kicking away the blocker.

Upvotes: 1

Views: 484

Answers (1)

user554538
user554538

Reputation:

So there are two things happening here. First, for the GIL itself, most of the I/O functions will release it just before calling into platform code, so a print call will definitely release it. This will naturally let the runtime schedule another thread.

Second, for usleep, this function is guaranteed to sleep at least as many microseconds as you ask for, but is pretty much not going to sleep less than the duration of the OS scheduler tick. On Linux this is often running at 1,000 Hz, 250 Hz, or 100 Hz, but can vary quite a bit.

Now, if you want something more granular than that, there's the nanosleep call which will "busy-wait" for delays shorter than 2 ms instead of calling into the kernel.

Upvotes: 2

Related Questions