Live data from Hacker News

Why Python Is Slow: Looking Under the Hood

jakevdp.github.io

1–10 of 156 posts

Re: Why Python Is Slow: Looking Under the Hood

#2
cPython does alot of work for just about any piece of code. Just a small handful of things:

1. everything's a hash (object data, variable lookup, etc). jmoiron wrote a great article on the topic http://jmoiron.net/blog/whats-going-on/

2. refcounting introduces overhead for every variable access

3. loops are making all kinds of function calls to __iter__, next(), and catching StopIteration, which makes it hard to have a tight loop.

4. There's the GIL, builtin locking isn't great.

5. lots of indirection (lack of value types)

Re: Why Python Is Slow: Looking Under the Hood

#5
Why, oh, why does CPython bother keeping refcounts for small integers? Sure, it lets you make pretty graphs with [sys.getrefcount(i) for i in range(1000)]... but that's an extra memory read and write on every instruction that uses an integer. I can only imagine that not only are these extra instructions, but they're extra instructions that kill pipelining, if the interpreter needed to do "a = 1; b = 1; c = 1" for instance. Maybe they found that the branch needed to not bother refcounting for small integers was even slower? Does anyone know if that was ever tried?

Re: Why Python Is Slow: Looking Under the Hood

#6
post #5

Why, oh, why does CPython bother keeping refcounts for small integers? Sure, it lets you make pretty graphs with [sys.getrefcount(i) for i in range(1000)]... but that's an extra memory read and write on every instruction that uses an integer. I can only imagine that not only are these extra instructions, but they're extra instructions that kill pipelining, if the interpreter needed to do "a = 1; b = 1; c = 1" for ins…

Does that also imply that a small integer is created on the heap? I would think the heap allocation would be the huge performance killer.

Re: Why Python Is Slow: Looking Under the Hood

#7
post #5

Why, oh, why does CPython bother keeping refcounts for small integers? Sure, it lets you make pretty graphs with [sys.getrefcount(i) for i in range(1000)]... but that's an extra memory read and write on every instruction that uses an integer. I can only imagine that not only are these extra instructions, but they're extra instructions that kill pipelining, if the interpreter needed to do "a = 1; b = 1; c = 1" for ins…

What you propose sounds like it would be a pure headache for all code which otherwise expects a uniform memory API.

Consider a C extension which takes an object and appends it to a list. If small integers did not have a refcount then that extension would have to have special code, like "if object is not a small integer, then increment the reference count".

Re: Why Python Is Slow: Looking Under the Hood

#8

cPython does alot of work for just about any piece of code. Just a small handful of things: 1. everything's a hash (object data, variable lookup, etc). jmoiron wrote a great article on the topic http://jmoiron.net/blog/whats-going-on/ 2. refcounting introduces overhead for every variable access 3. loops are making all kinds of function calls to __iter__, next(), and catching StopIteration, which makes it hard to have…

Well, it's hard to write an interpreter with the performance of, say, MRI Ruby.

Re: Why Python Is Slow: Looking Under the Hood

#9
post #5

Why, oh, why does CPython bother keeping refcounts for small integers? Sure, it lets you make pretty graphs with [sys.getrefcount(i) for i in range(1000)]... but that's an extra memory read and write on every instruction that uses an integer. I can only imagine that not only are these extra instructions, but they're extra instructions that kill pipelining, if the interpreter needed to do "a = 1; b = 1; c = 1" for ins…

There is no such thing as "small integers" in CPython, only PyObjects, of which PyInt_Type and PyLong_Type are implementations. You can't special case integers without changing every C interface that accepts an object, and special casing every piece of code too (i.e. several hundred million lines of 3rd party extension modules, NumPy, lxml, ...). The trade-off is 1 extra machine word per integer (adding to the 2 + heap/alignment slack already present), or 1 conditional branch per object access everywhere.

This isn't so bad on memory either, since Python keeps a static cache of integers that are reused on every int constructor call. Also allowing for slack, I wouldn't be surprised if the machine word came for free.

Re: Why Python Is Slow: Looking Under the Hood

#10
> 2. Python is interpreted rather than compiled.

Can we stop saying things like this? Virtually all Python is compiled, as part of the interpretation process.

There is a valid point here, of course. The point is that the top Python compilers do not compile to native code. So say that.

Words have meanings. Use them correctly.

Post reply on HN