Assignment Versus Equality

BartC bc at
Wed Jun 29 09:24:57 EDT 2016

On 29/06/2016 13:36, Steven D'Aprano wrote:
> On Wed, 29 Jun 2016 06:09 pm, Chris Angelico wrote:

>> That's not necessarily fair - you're comparing two quite different
>> Python interpreters, so there might be something entirely different
>> that counteracts the integer performance.

> No, my test doesn't precisely compare performance of boxed native ints
> versus boxed BigNums for the same version, but I don't care about that. I
> care about whether the Python interpeter is slower at int arithmetic since
> unifying int and long, and my test shows that it isn't.

> For int arithmetic, the answer is No. I can make guesses and predictions
> about why there is no performance regression:
> - native ints were amazingly fast in Python 2.7, and BigNums in Python 3.3
> are virtually as fast;
> - native ints were horribly slow in Python 2.7, and changing to BigNums is
> no slower;
> - native ints were amazingly fast in Python 2.7, and BigNums in Python 3.3
> are horribly slow, BUT object creation and disposal was horribly slow in
> 2.7 and is amazingly fast in 3.3, so overall it works out about equal;
> - int arithmetic is so fast in Python 2.7, and xrange() so slow, that what I
> actually measured was just the cost of calling xrange, and by mere
> coincidence it happened to be almost exactly the same speed as bignum
> arithmetic in 3.3.
> But frankly, I don't really care that much. I'm not so much interested in
> micro-benchmarking individual features of the interpreter as caring about
> the overall performance, and for that, I think my test was reasonable and
> fair.

I think there are too many things going on in CPython that would 
dominate matters beyond the actual integer arithmetic.

I used this little benchmark:

def fn():
     for i in range(1000000):

for k in range(100):

With CPython, Python 2 took 21 seconds (20 with xrange), while Python 3 
was 12.3 seconds (fastest times).

I then ran the equivalent code under my own non-Python interpreter (but 
a version using 100% C to keep the test fair), and it was 2.3 seconds.

(That interpreter keeps 64-bit integers and bigints separate. The 64-bit 
integers are also value-types, not reference-counted objects.)

When I tried optimising versions, then PyPy took 7 seconds, while mine 
took 0.5 seconds.

Testing the same code as C, then unoptimised it was 0.4 seconds, and 
optimised, 0.3 seconds (but n was declared 'volatile' to stop the loop 
being eliminated completely).

So the actual work involved takes 0.3 seconds. That means Python 3 is 
spending 12.0 seconds dealing with overheads. The extra ones of dealing 
with bigints would get lost in there!

(If I test that same code using an explicit bigint for n, then it's a 
different story. It's too complicated to test for C, but it will likely 
be a lot more than 0.3 seconds. And my bigint library is hopelessly 
slow, taking some 35 seconds.

So from that point of view, Python is doing a good job of managing a 
12-second time using a composite integer/bigint type.

However, the vast majority of integer code /can be done within 64 bits/. 
Within 32 bits probably. But like I said, it's possible that other 
overheads come into play than just the ones of using bigints, which I 
would imagine are streamlined.)


More information about the Python-list mailing list