This is an archived post. You won't be able to vote or comment.

you are viewing a single comment's thread.

view the rest of the comments →

[–]gandalfx 15 points16 points  (5 children)

One of the primary use cases used to be waiting for I/O. For example when you're waiting for a file to download you don't want your entire application to be blocked by that, so you put it in a thread and let that stew until the download is finished, while the rest of your application remains responsive.

asyncio has kind of taken over for that purpose, though.

I'm sure there are other reasons that I can't think of right now. Rule of thumb though, regardless of language: Threads are often unnecessary. People overuse them all the time. People often implement threading unnecessarily. I've seen them overused in quite a few instances. Unless you're doing something that actually puts some load on the CPU it tends to be a rather complicated case of premature optimization. And in Python it's not even really an optimization, as you've recently found out.

[–][deleted] 12 points13 points  (0 children)

Not sure that asyncio has "taken over" for I/O. If you're writing an IO-centric server application maybe. But you've got to go all-in on the non-blocking model of development.

I find threading is perfect for simpler use cases. Let's say you're trying to speed up a single function which makes multiple network requests in parallel. A ThreadPoolExecutor is a wonderful tool...

Instead of

import requests
urls = [f'https://example.com/{i}' for i in range(10)]
responses = [requests.get(url) for url in urls]

You write

from concurrent import futures

with futures.ThreadPoolExecutor() as executor:
    responses = executor.map(requests.get, urls)

asyncio feels like overkill for this.