Assignment Versus Equality

Steven D'Aprano steve at pearwood.info
Wed Jun 29 08:36:03 EDT 2016


On Wed, 29 Jun 2016 06:09 pm, Chris Angelico wrote:

> On Wed, Jun 29, 2016 at 4:45 PM, Steven D'Aprano
> <steve+comp.lang.python at pearwood.info> wrote:
>> On Wednesday 29 June 2016 15:51, Lawrence D’Oliveiro wrote:
>>
>>> On Wednesday, June 29, 2016 at 5:26:46 PM UTC+12, Steven D'Aprano wrote:
>>>> BUT in Python 3, the distinction between int and long is gone by
>>>> dropping int and renaming long as "int". So all Python ints are
>>>> BIGNUMs.
>>>
>>> I don’t understand what the problem is with this. Is there supposed to
>>> be some issue with performance? Because I can’t see it.
>>
>> If there is a performance hit, it's probably pretty small. It may have
>> been bigger back in Python 3.0 or 3.1.
>>
>> [steve at ando ~]$ python2.7 -m timeit -s "n = 0" "for i in xrange(10000): n
>> [+= i"
>> 100 loops, best of 3: 1.87 msec per loop
>>
>> [steve at ando ~]$ python3.3 -m timeit -s "n = 0" "for i in range(10000): n
>> [+= i"
>> 1000 loops, best of 3: 1.89 msec per loop
>>
>>
>> Although setting debugging options does make it pretty slow:
>>
>> [steve at ando ~]$ python/python-dev/3.6/python -m timeit -s "n = 0" "for i
>> [in
>> range(10000): n += i"
>> 100 loops, best of 3: 13.7 msec per loop
> 
> 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.

Um, the two code snippets do the same thing. Comparing two different
versions of the same interpreter is *precisely* what I intended to do:

- is CPython using boxed native ints faster than CPython using 
  boxed BigNums, post unification?


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 example: You're 
> creating and disposing of large numbers of objects, so the performance
> of object creation could affect things hugely.) 

Sure. But in real life code, you're likely to be creating and disposing of
large numbers of objects. And both versions create and dispose of the same
objects, so the test is fair to both versions.


> To make it somewhat 
> fairer, add long integer performance to the mix. Starting by redoing
> your test:

Why? That's irrelevant. The comparison I'm looking at is whether arithmetic
was faster using boxed native ints in older versions. In other words, has
there been a performance regression between 2.7 and 3.3?

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.

> rosuav at sikorsky:~$ python2.7 -m timeit -s "n = 0" "for i in
> xrange(10000): n += i"
> 10000 loops, best of 3: 192 usec per loop
> rosuav at sikorsky:~$ python2.7 -m timeit -s "n = 1<<100" "for i in
> xrange(10000): n += i"
> 1000 loops, best of 3: 478 usec per loop

Now *that's* an unfair benchmark, because we know that BigNums get slower as
they get bigger. A BigNum with 30+ digits is not going to perform like a
BigNum with 8 digits.

The right test here would be:

python2.7 -m timeit -s "n = 0L" "for i in xrange(10000): n += i"

On my machine, I get these figures:

[steve at ando ~]$ python2.7 -m timeit -s "n = 0" "for i in xrange(10000): 
n += i"
1000 loops, best of 3: 2.25 msec per loop
[steve at ando ~]$ python2.7 -m timeit -s "n = 0L" "for i in xrange(10000): 
n += i"
100 loops, best of 3: 2.33 msec per loop

which suggests that even in 2.7, the performance difference between native
ints and BigNums was negligible for smallish numbers. But of course if we
use huge BigNums, they're more expensive:

[steve at ando ~]$ python2.7 -m timeit -s "n = 1 << 100" "for i in
xrange(10000): n += i"
100 loops, best of 3: 2.44 msec per loop

although apparently not *that* much more expensive on my machine. Let's try
something bigger:

[steve at ando ~]$ python2.7 -m timeit -s "n = 1 << 1000" "for i in
xrange(10000): n += i"
100 loops, best of 3: 4.23 msec per loop

Now you can see the cost of really BigNums. But still, that's about 300
digits, so not too shabby.



-- 
Steven
“Cheer up,” they said, “things could be worse.” So I cheered up, and sure
enough, things got worse.




More information about the Python-list mailing list