Why does my Python thread block the main thread unless I add a print or a sleep?

81 Views Asked by At

Does anyone know why running this code causes the script to hang in the thread, unless I uncomment the print, the sleep, or the "if" condition, or remove the try/except? My understanding is that this thread shouldn't block the main thread.

import threading
import time  # noqa

class Something:
    def __init__(self):
        self.thread = threading.Thread(target=self.thread_loop, daemon=True)
        self.keep_looping = True
        self.a = 0

    def start_thread(self) -> None:
        self.thread.start()

    def stop_thread(self) -> None:
        self.keep_looping = False
        print('stop')

    def thread_loop(self) -> None:
        print('thread_loop')
        while self.keep_looping:
            try:
                # print('loop')
                # time.sleep(0.1)
                self.a += 1
                # if self.a == 'xxxx':
                #     print(self.a)
                #     time.sleep(0.1)
            except Exception as err:
                print(err)


blinky = Something()
print('start')
blinky.start_thread()
print('stop')
blinky.stop_thread()
print('done')
1

There are 1 best solutions below

0
larsks On BEST ANSWER

Does anyone know why running this code causes the script to hang in the thread...?

I don't see your script hanging. If I run it, unmodified, I see:

start
thread_loop
stop
stop
done

It's a little unclear what you're hoping to accomplish here; there's effectively zero time between your call to start_thread() and your call to stop_thread(), but since thread_loop() implements a strictly CPU-bound loop we can show that something is happening by adding an additional print to the end of your code:

blinky = Something()
print('start')
blinky.start_thread()
print('stop')
blinky.stop_thread()
print('done')
print(blinky.a)

Given the above code, we see:

start
thread_loop
stop
stop
done
159022

Showing us that thread_loop looped 159,022 times (the actual number will vary based on the speed of your CPU, the number of CPUs in your system, the number of other programs running, etc).

It's possible that on your system the loop in thread_loop is consuming so much of your CPU that nothing else has the time to run...in which case anything that explicitly sleeps (such as time.sleep()) or engages in i/o (such as a print statement) would yield control of the processor long enough for another thread to run.

Threading in Python is primarily useful when your code is not primarily CPU bound. Because of the global interpreter lock, multiple threads in Python are not able to run in parallel, leading to the situation I described in the previous paragraph.