Bob5421
Bob5421

Reputation: 9073

Python gil strange behaviour

Look at this piece of code:

from threading import Thread
import time

cpt = 0

def myfunction():
    print("myfunction.start")
    global cpt
    for x in range(10):
        cpt += 1
        time.sleep(0.2)
        print("cpt=%d" % (cpt))
    print("myfunction.end")

thread1 = Thread(target=myfunction)
thread2 = Thread(target=myfunction)
thread1.start()
thread2.start()

This is a very basic function which reads/write a global variable. I am running 2 threads on this same function.

I have read that python is not very efficient with multi-threading because of GIL, which automaticly locks functions or methods which access to the same resources. So, i was thinking that python will first run thread1, and then thread2, but i can see in the console output that the 2 threads are run in parallel. So i do not understand what gil is really locking...

Thanks

Upvotes: 0

Views: 118

Answers (1)

Jean-François Fabre
Jean-François Fabre

Reputation: 140188

That's because of the sleep system call which releases the CPU (and even "exits" from the interpreter for a while)

when you do time.sleep(0.2), the current thread is suspended by the system (not by Python) for a given amount of time, and the other thread is allowed to work.

Note that the print statements or threading.current_thread() that you could insert to spy the threads also yield (briefly) to the system so threads can switch because of that (remember Schrodinger's cat). The real test would be this:

from threading import Thread
import time

cpt = 0

def myfunction():
    global cpt
    for x in range(10):
        cpt += 1
        time.sleep(0.2)
    print(cpt)

thread1 = Thread(target=myfunction)
thread2 = Thread(target=myfunction)
thread1.start()
thread2.start()

Here you get

20
20

which means that each thread worked to increase the counter in turn.

now comment the time.sleep() statement, and you'll get:

10
20

which means that first thread took all the increasing, ended and let the second thread increase the further 10 counts. No system calls (even print) ensure that the GIL works at full.

GIL doesn't induce a performance problem, it just prevents 2 threads to run in parallel. If you need to really run python code in parallel, you have to use the multiprocessing module instead (with all its constraints, the pickling, the forking...)

Upvotes: 2

Related Questions