Live data from Hacker News

How many lines of C it takes to execute a + b in Python

codeconfessions.substack.com

41–50 of 224 posts

Re: How many lines of C it takes to execute a + b in Python

#41
post #4

A while back someone posted their patch to cpython where they replaced the hash function with a fast one and claimed this dramatically sped up the whole Python runtime. They claimed that the hash function was used constantly —e.g. 11 times in print("hello world")—because it's used to look up object properties. Apparently the default implementation is not optimized for performance but for security, just in case the so…

This may be a somewhat uninformed opinion, but I think CPython is just straight up not particularly good software. There are a million and one optimizations that other major scripting runtimes (V8, LuaJIT, PyPy, Ruby YJit etc.) have had for years that CPython is lacking. This is by design though. CPython has never been focused on performance, that's why it's not even JIT. It optimizes for simplicity and easy interope…

Python rather happened to have a language design and C API design that doesn't allow a simple performant implementation. Even PyPy was not that fast compared to other JIT implementations, while its C API support was always subpar. It is easy to say that Python should trade them off for performance, but they are one of the key reasons for Python's success after all.

Re: How many lines of C it takes to execute a + b in Python

#42
post #17
post #5

Sounds like it would be easier to just use C anyway.

Yes, but C is a much more arcane and complicated language. Case in point: instead of writing a+b in Python, in C you would have to write a+b (Jokes aside, it would really be more complicated in C if a and b were actually strings or lists.)

It still isn't simple

#! /Usr/bin/python

Print(a+b)

V

#include

Int main (){ Printf("%i", a+b); Return 0; }

And printf is basically a DSL, so it still isn't 'simple' And this is assuming a+b fits into an integer

Re: How many lines of C it takes to execute a + b in Python

#43
post #2

What's the answer?

It's hard to say. How many lines of code does it take to call

    typeobj->tp_as_number->nb_add()
when `tp_as_number` is a pointer to a `struct float_as_number`, and `nb_add` is a pointer to `float_add`?

Do struct definitions count as "lines of code called"?

Re: How many lines of C it takes to execute a + b in Python

#44
post #39

Earlier quoted context omitted.

to be concrete: fac = lambda n: 1 if n is 3 lines of python; how many lines of C code would it take to execute?

One: return 1.7112245243e98 Joking aside: these are not catch-all comparisons. Nor is the article. But Python is mucher slower and much safer than C. It's easier to start in Python than in C.

;-P Just to be pedantic, if you're going to all the trouble to give (modulo lack of a repl) a wrong answer fast, might as well do it really quickly:

    return 0;
in the hopes that compiles down to something like:

    xor rax, rax
    ret

Re: How many lines of C it takes to execute a + b in Python

#45

Earlier quoted context omitted.

This may be a somewhat uninformed opinion, but I think CPython is just straight up not particularly good software. There are a million and one optimizations that other major scripting runtimes (V8, LuaJIT, PyPy, Ruby YJit etc.) have had for years that CPython is lacking. This is by design though. CPython has never been focused on performance, that's why it's not even JIT. It optimizes for simplicity and easy interope…

Python rather happened to have a language design and C API design that doesn't allow a simple performant implementation. Even PyPy was not that fast compared to other JIT implementations, while its C API support was always subpar. It is easy to say that Python should trade them off for performance, but they are one of the key reasons for Python's success after all.

The semantic issues of making a performant Python language implementation are more or less exactly the same as for JS and Lua, optimizing Ruby seems to possibly have even more "magic" that needs patching but we've seen the Shopify team get cracking on that (it includes MaximeCB that did HiggsJS).

PyPy is in many aspects to be rated as a research project that tried a novel approach to reduce the workload compared to the manhours poured into V8,etc. LuaJIT managed with less with a focused language and a really capable lead. (Also I wouldn't be surprised if the PyPy team has also had to make compromises to get some kind of compatibility)

Re: How many lines of C it takes to execute a + b in Python

#46
post #37

This was quite interesting, but I’m disappointed it didn’t mention how many lines in C it actually took to run. Perhaps a profiler might help calculate this?

If you read the article you can see that some codepaths can invoke Malloc with all the follow-on effects like Kernel boundary crossings that this implies, it's thus quite random.

Re: How many lines of C it takes to execute a + b in Python

#47
post #17
post #5

Sounds like it would be easier to just use C anyway.

Yes, but C is a much more arcane and complicated language. Case in point: instead of writing a+b in Python, in C you would have to write a+b (Jokes aside, it would really be more complicated in C if a and b were actually strings or lists.)

C++ otoh is actually more arcane and complicated.

Re: How many lines of C it takes to execute a + b in Python

#48
post #16
post #9

Earlier quoted context omitted.

I'm aware that Rust has something similiar for things like `std::collections::HashMap`. By default: > The default hashing algorithm is currently SipHash 1-3, though this is subject to change at any point in the future. While its performance is very competitive for medium sized keys, other hashing algorithms will outperform it for small keys such as integers as well as large keys such as long strings, though those alg…

Python 3.11 appears to have switched to SipHash 1-3 for strings, from 2-4, following the lead of Rust and Ruby. https://github.com/python/cpython/issues/73596 However, Python does not use it for integers; >>> hash(10) 10 >>> hash(100) 100 >>> hash(2**61-2) == 2**61-2 True >>> hash(2**61-1) 0

That’s good though, right? Is there a reason for not using an identity hash (is that the right term?) for integers?

Re: How many lines of C it takes to execute a + b in Python

#49
post #7
post #3

Earlier quoted context omitted.

Running `__radd__(tyepof(b) b)` on `a` seems like a complicated problem. So: Many LoC? Or, the generic, useless but correct, answer: it depends (as the linked article said, too)

It shoud've been possible to establish the lower and upper bounds.

it's about as possible as solving the halting problem if you allow for operator overloading.

Re: How many lines of C it takes to execute a + b in Python

#50

Earlier quoted context omitted.

Python rather happened to have a language design and C API design that doesn't allow a simple performant implementation. Even PyPy was not that fast compared to other JIT implementations, while its C API support was always subpar. It is easy to say that Python should trade them off for performance, but they are one of the key reasons for Python's success after all.

The semantic issues of making a performant Python language implementation are more or less exactly the same as for JS and Lua, optimizing Ruby seems to possibly have even more "magic" that needs patching but we've seen the Shopify team get cracking on that (it includes MaximeCB that did HiggsJS). PyPy is in many aspects to be rated as a research project that tried a novel approach to reduce the workload compared to t…

Unfortunately Python's innard is much more complicated than most expectations. You have named JS and Lua, but those languages never have "magic" methods---JS instead has prototypes and more recently proxies, while Lua has metatables. Ordinary objects aren't magic in this sense, and conversely magical objects are generally deliberate choices in those languages. But Python's magic `__dunder__` methods are everywhere including ordinary objects (and customized objects that look like ordinary objects, e.g. `list` subclasses). That alone complicates a lot of things.
Post reply on HN