Live data from Hacker News

Why Python Is Slow: Looking Under the Hood

jakevdp.github.io

71–80 of 156 posts

Re: Why Python Is Slow: Looking Under the Hood

#71
post #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".

I have experience turning a Lisp dialect with refcounted integers into supporting non-refcounted integers, identified by a type tag field in the "value cell" type.

> 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".

Easily implemented in one place in the "increment_refcount(obj)" inline function:

    // roughly speaking
    if (is_heap_pointer(obj))
      obj->refcount++;
where "is_heap_pointer(obj)" is an inlined bitmask check like

    (((unsigned int) obj) & TAG_MASK) == TAG_PTR)
If TAG_PTR is zero bits, then a value which satisifes is_heap_pointer can be dereferenced straight.

In a garbage collection implementation, you don't have refcounts, but the garbage collector's "mark object" function does the same check:

   if (!is_heap_pointer(obj))
     return;  // don't try to mark non-heap things

   switch (type(obj)) {
   case TYPE_CONS_CELL
      mark_obj(obj->cons.car);
      mark_obj(obj->cons.cdr);
      break;
   // ...
   }
Another thing is that you provide an API to the extension writers, which abstracts the use of objects. For instance, you can give them a function that can be called like this:

   value n = number(42);
   value z = number(INT_MAX);
The first case might construct an unboxed value because the integer is small enough. But perhaps the second returns a bignum because INT_MAX requires 32 bits, wheres unboxed integers only go up to 30 bits.

So in the first case you get an object with no refcount, whereas in the second you get an object with a refcount of 1. The extension code is written such that it doesn't care.

Re: Why Python Is Slow: Looking Under the Hood

#72
post #25

Heh, Python is slow: in order to write fast Python, you have to write in C and conform to the FFI. I vastly prefer to use tools which don't come misshapen out of the box, personally.

Different tools for different jobs. Being able to develop code quickly is a huge win that Python delivers. Sometimes that makes Python the right tool, e.g. Youtube. Other times slow execution speed makes it the wrong choice.

[0] http://www.gooli.org/blog/youtube-runs-on-python/

Re: Why Python Is Slow: Looking Under the Hood

#73
post #64
post #43

Earlier quoted context omitted.

Is it just me who sees a large chunk of these as flaws in the Python implementation as opposed to the Python language? There are a number of design decision in python language that makes it inherently hard to write a fast python implementation.

Ah, the right answer! There are lots of languages where variables are dynamically typed that can be compiled and optimized with a JIT compiler. In Python, though, any code can mess with any data, using "setattr". You can find all the variables in another module and mess with them at run time, using their names as strings. At compile time, the compiler can't detect that's going to happen. This is sometimes called the…

How is python substantially different from javascript in this case? Google has a crazy fast javascript JIT compiler, even though javascript has something equivalent to python's setattr().

Re: Why Python Is Slow: Looking Under the Hood

#74

A related question is: why is Perl so fast? Quite a few years ago I wrote a little Runge-Kutta solver in Perl for some simulation work. It seemed like a good idea at the time. The equations of motion had to be integrated over a very long time, and it could take hours for a single run (still much faster than the Monte Carlo it was being used to do a sanity-check on). I re-wrote everything in C++, and picked up less th…

"oh my god it's full of whitespace"

When I write in python, this always triggers my mental slogan "python, the language which makes 'nothing' important".

This is said with a trace of irony, as my most fluent language is bash scripting :)

Re: Why Python Is Slow: Looking Under the Hood

#75

A related question is: why is Perl so fast? Quite a few years ago I wrote a little Runge-Kutta solver in Perl for some simulation work. It seemed like a good idea at the time. The equations of motion had to be integrated over a very long time, and it could take hours for a single run (still much faster than the Monte Carlo it was being used to do a sanity-check on). I re-wrote everything in C++, and picked up less th…

>related question is: why is Perl so fast?

Easy answer: it's not. On most benchmarks it's on par with Python, PHP, Ruby, etc, some are faster on one, others on some other test.

>once I got over the "oh my god it's full of whitespace" thing

What full of whitespace? Python has as much (or as little) whitespace as normally intended Perl, Ruby, C, etc.

What it has that they don't have is significant whitespace.

Re: Why Python Is Slow: Looking Under the Hood

#76
post #73
post #64

Earlier quoted context omitted.

Ah, the right answer! There are lots of languages where variables are dynamically typed that can be compiled and optimized with a JIT compiler. In Python, though, any code can mess with any data, using "setattr". You can find all the variables in another module and mess with them at run time, using their names as strings. At compile time, the compiler can't detect that's going to happen. This is sometimes called the…

How is python substantially different from javascript in this case? Google has a crazy fast javascript JIT compiler, even though javascript has something equivalent to python's setattr().

> even though javascript has something equivalent to python's setattr().

Python provides significantly more hooks into the behaviour of arbitrary objects, and arguably provides more flexibility than JS.

Here are a few notes from Mike Pall (LuaJIT) on Python features making a straight interpreter slower, and the language harder to optimise (JIT tightly): http://lua-users.org/lists/lua-l/2004-11/msg00083.html

Animats is full of shit, the ability to add arbitrary "static" attributes to existing objects is really not the main problem.

Re: Why Python Is Slow: Looking Under the Hood

#77

A related question is: why is Perl so fast? Quite a few years ago I wrote a little Runge-Kutta solver in Perl for some simulation work. It seemed like a good idea at the time. The equations of motion had to be integrated over a very long time, and it could take hours for a single run (still much faster than the Monte Carlo it was being used to do a sanity-check on). I re-wrote everything in C++, and picked up less th…

I'm not sure your results are typical. In microbenchmarks, Perl is 2-125x slower than C++: http://benchmarksgame.alioth.debian.org/u32/benchmark.php?te... And Java is quite a bit faster than Perl too: http://benchmarksgame.alioth.debian.org/u32/benchmark.php?te... Perl isn't really that fast. It's faster than Python in most cases, but gets beat by Lua pretty consistently: http://benchmarksgame.alioth.debian.org/u32/b…

For a general-purpose problem, Perl won't be particularly fast. For a Perl-type problem (scanning and parsing big files), Perl is very fast.

Doing a Perl-type problem in a general-purpose language would be considerably slower. However, Python or others will perform much better in the "can I read my own code six months later" benchmark.

Re: Why Python Is Slow: Looking Under the Hood

#79
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.

Python is not going to call malloc(..) for every single object that you create. It will allocate a block of same-sized objects and maintain a linked list of free slots.

Re: Why Python Is Slow: Looking Under the Hood

#80
Please forgive my ignorance, but why can't Python just be compiled into assembly like C? The compiler should be able sift through the code and see that "x=1" is an integer, or converts to a float when "x=x+1.0".

If I'm doing something like counting from 1 to 10 and summing the count, why can't this be compiled to run the same speed as C?

Obviously since it's interpreted, but when I'm done with development, why can't I just run it through a compiler to get fast assembly code?

Way back when, you could get a BASIC compiler to turn your interpreted BASIC code into assembly.

What fundamental am I missing?

Post reply on HN