Live data from Hacker News

Overhead of Python asyncio tasks

textual.textualize.io

31–40 of 88 posts

Re: Overhead of Python asyncio tasks

#31
post #21

Async Python is still confusing af - when do I need it, what happens under the hood, does it actually help with performance, sometimes the GIL comes into play and sometimes it doesn't, why do we ever use threads at all if there's a GIL, why is it called async io if we can use it for anything. My mind is kind of scattered and people seems to be using a lot of async Python for some reason. Any good resources to clear t…

It makes concurrent programming much simpler than using threads.

Very few locking and care is needed with asyncio, as opposed to using threads. Race conditions are basically not a thing if you write reasonably idiomatic code.

It might be (or not) faster than using threads, but that's not the main benefit in my view - this easiness of use is.

Re: Overhead of Python asyncio tasks

#32

So, 250,000 per second on a (roughly 10,000 MIPS I7 core) Each of those task_create calls is roughly 10,000,000,000 / 250,000 = 40,000 instructions. Thats 40'000 instructions of pure overhead as it does not contribute to the task at hand (accidental complexity).

Your method of estimating instructions includes printing multiple lines which context switch to the kernel to perform IO. I'm not sure how an "instruction count" metric is useful anyway. edit: I'm not actually sure you are counting the context switch, but I still don't think estimating instruction count that way is particularly useful.

Its useful to show how much waste there is in a solution.

Having an operation that can be executing 250,000 times per second on a modern processor is extremely slow... not fast.

Re: Overhead of Python asyncio tasks

#33

After running that code on both a Windows SB3 and major souped up Lenovo running Ubuntu...I just feel inadequate.

Python 3.11 running in a-Shell on an M1 iPad Pro

    Python 3.11.0 (heads/3.11-dirty:8d3dd5b9647, Dec  7 2022, 08:17:48) [Clang 14.0.0 (clang-1400.0.29.202)]
 on darwin
    Type "help", "copyright", "credits" or "license" for more information.
    >>> 
    [~/Documents]$ python test.py
    100,000 tasks    127,992 tasks per/s
    200,000 tasks    115,960 tasks per/s
    300,000 tasks    117,205 tasks per/s
    400,000 tasks    113,131 tasks per/s
    500,000 tasks    109,609 tasks per/s
    600,000 tasks    116,649 tasks per/s
    700,000 tasks    110,743 tasks per/s
    800,000 tasks    111,361 tasks per/s
    900,000 tasks    109,688 tasks per/s
    1,000,000 tasks          117,064 tasks per/s

Re: Overhead of Python asyncio tasks

#35
post #21

Async Python is still confusing af - when do I need it, what happens under the hood, does it actually help with performance, sometimes the GIL comes into play and sometimes it doesn't, why do we ever use threads at all if there's a GIL, why is it called async io if we can use it for anything. My mind is kind of scattered and people seems to be using a lot of async Python for some reason. Any good resources to clear t…

It's great for when you can do concurrent I/O tasks. For example running a web backend, web scraping, or many API calls. FastAPI (and Starlette that it's built off of) is an async web framework and in my experience performs well.

Basically, your program will normally halt when doing I/O, and won't proceed until that I/O is done. During that halt, your program is doing nothing (no cpu being used). With asyncio, you can schedule multiple tasks to run, so if one is halted doing I/O, another can run.

Edit: And AFAIK, the GIL does not come into play at all with async. Only when multithreading.

Re: Overhead of Python asyncio tasks

#37
post #22

What a fun experiment. I quick converted it to Go using goroutines and waitgroups for fun: https://gist.github.com/schmichael/1a417808b8e88b684838ae9f4...

I am seeing 500~600k tasks/second in .NET6 w/ TPL. Edit: Updating per request below. Tested on a TR2950x. I wonder if NUMA issues in my case or bad python version (3.9.4). Python 100,000 tasks 77,108 tasks per/s 200,000 tasks 69,945 tasks per/s 300,000 tasks 72,453 tasks per/s 400,000 tasks 74,636 tasks per/s 500,000 tasks 66,253 tasks per/s 600,000 tasks 77,576 tasks per/s 700,000 tasks 69,673 tasks per/s 800,000 ta…

[dead]

Re: Overhead of Python asyncio tasks

#38
post #14

Why would you want a terminal emulator anywhere near python? Using python for lightweight system utility gui apps seems like using a hammer to screw in a nail. Yeah you can do it and modern hardware is fast enough that you probably won't care, but why??

[flagged]

Re: Overhead of Python asyncio tasks

#39
post #21

Async Python is still confusing af - when do I need it, what happens under the hood, does it actually help with performance, sometimes the GIL comes into play and sometimes it doesn't, why do we ever use threads at all if there's a GIL, why is it called async io if we can use it for anything. My mind is kind of scattered and people seems to be using a lot of async Python for some reason. Any good resources to clear t…

I agree that especially within the standard context of python and its syntax, async seems weird (because it's sprinkled into an existing paradigm).

The best mental model for me always was to think: Here's an await, that means "interpreter, go and do something else that's currently waiting while this is not done yet."

And that's all about IO, because what you can wait on is essentially IO.

By the way, I really wish there was a better story to executors in async python. To think we still have the same queue/pickle-based multiprocessing to send async tasks to another core is kind of sad. Hoping for 3.12 and beyond there.

[edit] one really neat example that helped me get asyncio was Guido van Rossum's crawler in 500 lines of python [1]. A lot of the syntax is deprecated now, but it's still a great walk-through

[1] http://aosabook.org/en/500L/a-web-crawler-with-asyncio-corou...

Re: Overhead of Python asyncio tasks

#40

Earlier quoted context omitted.

Your method of estimating instructions includes printing multiple lines which context switch to the kernel to perform IO. I'm not sure how an "instruction count" metric is useful anyway. edit: I'm not actually sure you are counting the context switch, but I still don't think estimating instruction count that way is particularly useful.

Its useful to show how much waste there is in a solution. Having an operation that can be executing 250,000 times per second on a modern processor is extremely slow ... not fast.

Waste allows scale, that's a general civilizational rule.

You wouldn't be able to write your comment if the browser were written in extremely efficient assembly code because it wouldn't exist.

NASA and every big organization also has a lot of waste, but only that way you can get to the moon.

Post reply on HN