Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Python threads and GIL

Let's say I have a thread and the main part of the program. Because of GIL, one thread should work at a time right (and not simulatenously)? But what if One of the threads is an infinite loop (or both for that matter)?

Would these two processes run in parallel?

def test():
    while True:
       print "hello"

def test2():
    while True:
       print "hi"

def start_thread():
    try: 
        thread.start_new_thread( test2,() )
    except:
        print "Error: Unable to start thread"
start_thread()
test()
like image 794
Luis Cruz Avatar asked Apr 17 '15 16:04

Luis Cruz


People also ask

What is the point of Python threads?

Threading in python is used to run multiple threads (tasks, function calls) at the same time. Note that this does not mean that they are executed on different CPUs. Python threads will NOT make your program faster if it already uses 100 % CPU time.

Is CPython thread-safe?

Python is not by its self thread safe. But there are moves to change this: NoGil, etc. Removing the GIL does not make functions thread-safe.


1 Answers

They'll run concurrently, but not actually in parallel. The OS will frequently switch back and forth between the two threads, so that they'll both be able to get their work done. This is what is meant by "concurrent"; one thread doesn't need to wait for the other to finish before it can start working. But because of the GIL, they'll never both actually be running at the exact same time, where each is being run on a different core in parallel. Each thread will run for a bit, pause while the other thread runs, then start running again, then pause, etc.

This is easy enough to see if you just run your example code. Here's the output on my machine:

hello
hi
hello
hi
hello
hi
hello
hi
hello
hi
hello
hi
hello
hi
hello
hi
hello
hi

Clearly, both threads are running. Each thread is just running slower than it would be if only one thread was running in the program.

Consider this example, where each thread calculates the fibonacci sequence:

import thread
import time


def fib(n):
    if n <= 1:
        return n

    return fib(n-1) + fib(n-2)

def test():
    while True:
       start = time.time()
       out = fib(32)
       print "hello %s: %s" % (out, str(time.time() - start))

def test2():
    while True:
       out = fib(20)

def start_thread():
    try: 
        thread.start_new_thread( test2,() )
    except:
        print "Error: Unable to start thread"
#start_thread()
test()

With just test running (so no second thread), I get this output:

hello 2178309: 0.953778982162
hello 2178309: 0.954975128174
hello 2178309: 0.95578789711
hello 2178309: 0.949182033539

If I start up test2 in the background as well, I get this:

hello 2178309: 4.07990288734
hello 2178309: 4.08523893356
hello 2178309: 2.51651597023
hello 2178309: 2.13291287422
hello 2178309: 2.19885015488

As you can see, performance takes a huge hit.

Note that if one of the threads is doing something that releases the GIL - like blocking I/O, or calling into a C library that releases the GIL - you won't see this kind of performance degradation, because in that case both threads actually can run in parallel. This doesn't apply in the above example, since neither thread is doing work that releases the GIL.

like image 175
dano Avatar answered Sep 22 '22 00:09

dano