The Cost of Dynamism (was Re: Pyhon 2.x or 3.x, which is faster?)

Steven D'Aprano steve at pearwood.info
Fri Mar 25 22:19:37 EDT 2016


On Sat, 26 Mar 2016 09:08 am, BartC wrote:

> On 25/03/2016 16:22, Steven D'Aprano wrote:
>> On Fri, 25 Mar 2016 10:06 pm, BartC wrote:
> 
> (OK, I'll risk the wrath of Mark Lawrence et al by daring to post my
> opinions.)

Please ignore Mark Lawrence when he is acting as an obnoxious troll, as he
is now. He occasionally has something useful or helpful to say, but most of
the time he thinks he is the self-appointed Guardian of Python's Honour, a
job he is singularly ill-equipped for even if Python's honour needed
defending, which it doesn't.


>>> But it is an optimisation that /could/ be done by the byte-code compiler
> 
>> I would also expect that Victor Stinner's FAT Python project will
>> (eventually) look at optimizing such for-loops too. If you see something
>> like:
>>
>> for i in range(N):
>>      do_stuff()
>>
>>
>> and three conditions hold:
>>
>> (1) i is unused in the loop body;
>>
>> (2) range is still bound to the expected built-in function, and no
>> other "range" in a nearer scope (say, a local variable called "range", or
>> a global) exists to shadow it; and
> 
> The volatility of 'range' I'd completely forgotten about. Python really
> doesn't make this stuff easy, does it?

True. But it makes *other things* much more easy. Things which are
impossible or very difficult in other, stricter languages are trivially
easy in Python.



> Checking this at runtime, per loop (I don't think it's necessary per
> iteration) is a possibility, but now an extra overhead is introduced. It
> might worth it if the body of the loop is also optimised, but this is
> getting into the territory covered by tracing JITs.

Detecting whether or not range has been shadowed or replaced doesn't need a
full tracing JIT. Victor's work isn't complete, but preliminary results
suggest strongly that the overhead of checking guards will be
insignificant.


> My kind of approach would try to keep it simple, and that would be
> helped tremendously by special language constructs (something like
> Ruby's 100.times) where you can use a streamlined loop, and possible
> unrolling, straight off.

Ruby is an interesting case, because Ruby is even more dynamic than Python.
Python doesn't allow you to replace or add methods to built-ins, but Ruby
does, so in principle, you have no idea what 100.times is going to do until
runtime. That's no different from Python and range.

Up until a few years ago, Ruby was considered even slower than Python, by a
factor of two or five or so. I'm lead to believe that the latest version of
Ruby reverses that, and I've seen claims that it is now faster than Python,
but I haven't seen it for myself so I'm not sure if I believe it entirely.


> (Personally, if I was creating a byte-code intepreter for Python as-is,
> I would have a -dynamic:on or -dynamic:off switch.)
> 
>> Here is one of the oldest:
>>
>> http://www.ibm.com/developerworks/library/l-psyco/index.html
> 
> Yes, I tried that long ago. It's very fast on certain benchmarks. (Both
> psyco and pypy can run my lexer at around 170Klps. And this is code
> using string compares and long if-elif chains, that would be crazy in
> any other language. From that point of view, it's very impressive (I can
> only get half that speed using the same methods).

The Python philosophy seems to prefer the use of specialist JIT compilers to
speed up bottlenecks rather than language features. I've seen Guido comment
that he doesn't believe static AOT optimization is worthwhile in Python and
that people should concentrate on JIT optimizations. I suspect he's right.



-- 
Steven




More information about the Python-list mailing list