13

I heard threading is not very efficient in Python (compared to other languages).

Is this true? If so, how can a Python programmer overcome this?

5
  • 7
    Note that the GIL is only present in CPython. You could still use something like IronPython and not incur (as many) penalties for using threads. Commented Feb 26, 2011 at 16:21
  • I actually heard it is quite efficient. Commented Feb 26, 2011 at 16:26
  • Can someone post some links to issues/or non issues with multithreading in python? Commented Feb 26, 2011 at 16:30
  • 1
    wiki.python.org/moin/GlobalInterpreterLock Commented Feb 26, 2011 at 16:34
  • 1
    There are already a lot of questions regarding threading and python .... Commented Feb 26, 2011 at 16:36

6 Answers 6

23

The reason people say that multi-threading is not very efficient in python is because of the Global Interpreter Lock. Because of the way the interpreter is written, only one thread can safely execute code in the interpreter at the same time.

This means that if you have threads which are quite heavily compute bound, that is, doing lots of stuff in the interpreter, then you effectively still only have the performance of a single threaded program. In this case you might be better off using the multiprocessing module, which has the same interface as the multithreading module but launches multiple copies of the interpreter (the downside of this is that you will have to explicitly share memory).

Where you still can reap speed gains from multithreading in python is if you are doing something that is heavily IO bound. While one thread is waiting for disk or network i/o the other threads can still execute, because when threads block they release the interpreter lock.

Sign up to request clarification or add additional context in comments.

1 Comment

Or even worse performance that a single threaded program: see this excellent talk by Dave Beazley, Understanding the GIL for an in depth view.
13

CPython uses reference counting with a cyclic garbage collector for memory management. To make this practical, it has a mechanism called the "global interpreter lock" which protects the reference counting system, along with all the other interpreter internals.

On a single-core machine, this doesn't matter - all threading is faked via time-slicing, anyway. On a multiple core machine, it makes a difference: a CPU bound Python program running on CPython won't make use of all of the available cores.

There are a number of possible responses to this:

  • use multiple processes instead of multiple threads (also opens up future scalability to multiple machines, rather than different cores within a single machine)
  • use a Python implementation with a more multicore friendly garbage collection mechanism (such as Jython, IronPython or PyPy)
  • move the more intensive CPU operations out to C code and release the GIL while doing the calculations (thus allowing the C code to run on other cores even though only a single Python thread is active at any one time)

If threads are being used to convert blocking IO to a non-blocking operation, then that works just fine in standard CPython without any special modifications - IO operations already release the GIL.

Comments

8

You overcome this by using multiprocessing instead! It's as simple as multithreading in python but gives you the full power of all your cpu cores.

multiprocessing is a package that supports spawning processes using an API similar to the threading module. The multiprocessing package offers both local and remote concurrency, effectively side-stepping the Global Interpreter Lock by using subprocesses instead of threads. Due to this, the multiprocessing module allows the programmer to fully leverage multiple processors on a given machine. It runs on both Unix and Windows.

Comments

2

One option is to use a different implementation of Python, like Jython or IronPython. That way, you still get the benefits of having the Python language without having to deal with the GIL. However, you wouldn't have the ability to use the CPython-only libraries.

Another option is to use different constructs than threads. For example, if you use Stackless Python, Tasklets are an alternative.

Comments

1

The threading is efficient in CPython, but threads can not run concurrently on different processors/cores. This is probably what was meant. It only affects you if you need to do shared memory concurrency.

Other Python implementations does not have this problem.

Comments

-1

after finding solution (below) I wonder why python still has threading class

from multiprocessing import Pool def some_function(x): return x*x Xs = [i for i in xrange(1, 1000)] # make 1, 2, ..., 999, 1000 pool = Pool(processes=16) # start 16 worker processes on 16 CPU print pool.map(some_function, Xs) # print out 

1 Comment

Because the Thread class and Pool class are for two different things.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.