r/pythoncoding Jul 19 '24

Coming from Java, I am confused about whether Python has real threads or not.

I have read about the Global Interpreter Lock (GIL) and understand that it is a lock per interpreter in Python, which is historical. However, I still see thread packages in Python. Why are they there if the GIL exists? What's the point?

So, what is the verdict here?

Thanks

8 Upvotes

7 comments sorted by

3

u/TheBlackCat13 Jul 19 '24

Some stuff, particularly C code, can release the GIL while it is processing. This allows other threads to run. But it is the exception, so it can only be useful in very limited circumstances.

1

u/Peaceful-Absence Jul 19 '24

Python does have real threads, but they are not effective for CPU-bound operations.

However, I/O operations or network operations can run simultaneously on threads because they spend a lot of time waiting for external resources, and the GIL is released during these waits.

Additionally, GIL doesn't affect GPU-bound operations like AI model inference. In my current project, I compared the performance of threads vs. multiprocessing and they were identical.

1

u/audentis Sep 04 '24

In my current project, I compared the performance of threads vs. multiprocessing and they were identical.

Without knowing more about your project, odds are the libraries you're using already use parallel C-code under the hood.

1

u/BlanketSmoothie Jul 23 '24

Concurrency is not parallelism.

2

u/audentis Sep 04 '24 edited Sep 04 '24

There's a great keynote from Raymond Hettinger about concurrency in Python. It discusses the differences between threading, async, and multiprocessing.

In Python, threads are real but hamstrung by the GIL. Threading primarily helps with concurrent IO like filesystem calls or web requests, but as you properly identified, the GIL won't allow Python code to run concurrently in threads. Nowadays, async is preferred over threading for most use cases. Async was added much later to the language than threading (3.4 vs 3.0), but it took over all those use cases in a more convenient way because you can control when the task switching occurs (and therefore maintain coherent state).

With the multiprocessing library, you can get fully concurrent Python code. Each process has its own GIL. But being separate processes, the interproces communication is also more difficult. A good use case for this is simulation: usually you want to run the same model with different parameters. Each model execution is independent. You can write a script to run each configuration in a different process, so that all scenarios are executed concurrently, while each individual simulation is fully sequential and therefore easy to write.

By the way, in newer Python versions there's an ongoing effort to remove the GIL.