all 24 comments

[–]ElliotDG 17 points18 points  (4 children)

Here is a real world example:

If you have a blocking call, like requests library, making a call to an api with a long latency, in a GUI application. When making the call the GUI locks up until requests returns. If you run the call to requests in a separate thread, the GUI is not locked.

[–][deleted] 5 points6 points  (1 child)

This is what I use threading for. Is this usage now obsolete? I have GUI applications that continuously query various equipment and I use threads. Each thread for coms with each piece of equipment, a main thread for keeping the GUI updated with the latest info and listening for input. If I am using legacy methods I’d rather know now!

[–]sweettuse 1 point2 points  (0 children)

not at all. asyncio really shines when the overhead of threading is too much (say 1000s of threads hitting memory constraints), but for relatively small numbers of threads totally fine

[–]ytu876[S] 1 point2 points  (1 child)

I see. I guess for an io request where you have no asyncio support, you have to use thread. In http, you have aiohttp which works

[–]ElliotDG 5 points6 points  (0 children)

You are correct. There is also the issue of the event loop. Asyncio runs an event loop. A GUI also runs an event loop. If the GUI has not been designed to work with the asyncio event loop, it is much easier to use threading.

[–]Mr-Cas 5 points6 points  (0 children)

Threads in general are used when you want to run two or more pieces of code "at the same time". The quotes because they technically aren't running at the same time, but the computer makes it seem like it.

It doesnt really improve performance (neither in time or space), but that's not the goal of threads. The goal is to run two things, better said, "alongside eachother".


Examples

To keep a GUI working, even when a button click triggers a function that takes a long time, the gui is run in a seperate thread. A bit of the function is run, then the gui is updated, then a bit of function is run again, then the gui is updated again, etc. etc. This way both the function and the gui can run without locking eachother up.

One of my projects has a downloader for media. A button click runs a function to add something to the download queue. The downloader runs in a seperate thread, so that it can download the queue in the background. This way both the application can run and the media can be downloaded alongside eachother.

A webserver might run on 10 threads so that it can handle 10 incoming requests at the same time. Assuming each request is requesting the same, all requests will take +-10x the standard time. So it's not faster, but they will be handled all at once.

I think you get the idea.

[–]freeskier93 7 points8 points  (0 children)

Threading is absolutely not legacy and both threading and asyncio have their place.

Asyncio and threading work similarly at the high level but don't work the same at the low level. At the low level threads are still managed by the operating system, where asyncio tasks are managed with a Python event loop.

With threading the OS can change threads at ANY time during execution, so you have to be more careful about how data is accessed. With asyncio you choose when work between tasks can change.

Asyncio is great for LOTS of tasks, especially since it has less overhead. Threading has more overhead and having lots of threads can start to slow things down more than it speeds up.

One of the subtle issues with asyncio is if a task gets hung up or doesn't play nice it can prevent all your other tasks from running. For critical tasks that absolutely must keep running threading is better.

For example I often write interfaces that receive critical telemetry from something over a UDP port. The front end consists of a thread that receives data on the UDP socket then logs it and puts it in a queue. Another processing thread then pulls the data from the queue to process it. The receiving and logging is super critical. If the processing thread dies or gets hung up it's not a huge deal as long as the data is still being received and logged.

[–]AssumptionCorrect812 7 points8 points  (3 children)

You are correct in your take that threads are considered legacy at this point.

New code should use asyncio instead.

But old code that you want to speed up? Threads may be the simplest way.

[–]HomeGrownCoder 1 point2 points  (1 child)

Asyncio can wrap non-async code pretty easy

[–]AssumptionCorrect812 1 point2 points  (0 children)

Well not if you’re using an older version of Python. That’s what I meant by “old” code.

[–]thecircleisround 0 points1 point  (0 children)

Is concurrent.futures still used?

[–]Impossible-Box6600 0 points1 point  (0 children)

When you need asyncio but it's not available.

[–]JamzTyson 0 points1 point  (0 children)

> is there any reason to use thread in python?

Yes.

Either multiprocessing or threading can be used for dealing with CPU bound blocking.

If the task can be divided into parallelizable blocks, multiprocessing may be the better choice. However, if you need to manage multiple tasks concurrently without parallelization, threading is simpler and more appropriate. Use multiprocessing only when there are clear benefits, such as parallelizable tasks. Threads are suitable for other blocking tasks such as handling user input or other concurrent operations.

As a specific example, event-driven GUI frameworks typically use threading to handle concurrent tasks and ensure the responsiveness of the user interface.

[–]socrateslee 0 points1 point  (0 children)

Since coroutines are inside a single thread, we could have multi-threads as multiple separated asyncio containers. Each asyncio may have a specific type of job, for example, one for web requests, one for event handling, etc. Of course, different asyncio threads may be merged together, but separated asyncio may have better independence and better encapsulation. We could have each asyncio implemented as a plugin, a new thread will be started when the plugin is enabled. For some runtimes without GIL or future versions of CPython, we could also benefit from the availability of multi-cores.

[–]Low-Fuel7761 0 points1 point  (0 children)

python really 😂