4 ms·
You can make a Python-ish language that can run fast (or at least, a lot faster) but it cannot be Python: the dynamic nature of the language means many optimizi
by __d 3y ago
You can make a Python-ish language that can run fast (or at least, a lot faster) but it cannot be Python: the dynamic nature of the language means many optimizing techniques just aren't available.
The unfortunate thing is that the vast majority of Python code in use today doesn't need all those super-dynamic features. So it would run just fine on a cut-down JITed interpreter. But there's always the corner cases.
In retrospect, Python 3 was a lost opportunity here: it could have broken more compatibility, enabled multi-core and JITs, and then the 10 year transition pain would actually have been worth it. But that's hindsight, of course.
- fuc____d 3y ago[dead]
- chlorion 3y ago>the dynamic nature of the language means many optimizing techniques just aren't available. This is something that seems like it should be true, but counter evidence exists that proves that it's not the case. The first example would be V8, the JavaScript JIT compiler used in Chrome and NodeJs (and probably other things). V8 is many times faster than CPython in pretty much every situation. The second, and even better example is SBCL, a Common Lisp compiler. SBCL is quite a bit faster than CPython and V8, it's closer to the JVM in terms of performance in benchmarks that I have saw. The third example would be some of the Scheme compilers, like Chez and Gambit, which are not far off from SBCL. Maybe you could argue that JavaScript is not as dynamic as Python. I don't know JavaScript at all so maybe that is the case. I'm pretty sure that Common Lisp and Scheme are not less dynamic though. I think Common Lisp is actually more dynamic but I don't have any way to measure this, so it's just my opinion. So assuming these languages are as or more dynamic than Python, this seems to be proof that Pythons dynamic-ness is not the reason for it's poor performance! The Lisp compilers are also much less widely used and have much less engineering power available! I think these counter examples are pretty interesting and don't know exactly what to make of it. Python has more funding and more users to contribute to it (except in the case of V8), I guess until now they just haven't put any of that into performance.
- kazinator 3y agoPython is "stupid dynamic"; it exposes implementation details which can't work work well under compilation, like accessing a caller's local variables.
- chlorion 3y agoYes, but Common Lisp is also "stupid dynamic"! I don't think there's anything Python can do that Common Lisp can't in terms of dynamic-ness! This is a quote from python.org: >These languages are close to Python in their dynamic semantics, but so different in their approach to syntax that a comparison becomes almost a religious argument: is Lisp's lack of syntax an advantage or a disadvantage? It should be noted that Python has introspective capabilities similar to those of Lisp, and Python programs can construct and execute program fragments on the fly. Usually, real-world properties are decisive: Common Lisp is big (in every sense), and the Scheme world is fragmented between many incompatible versions, where Python has a single, free, compact implementation. https://www.python.org/doc/essays/comparisons/ https://www.python.org/doc/essays/comparisons/ I believe there are dynamic things Common Lisp can do that python can't, like modifying and creating classes, inheritance and methods at runtime, even with effects propagating out to already existing class instances!
- lispm 3y ago> Yes, but Common Lisp is also "stupid dynamic"! It's not. Common Lisp was designed to enable Lisp applications to be delivered with reasonable performance, first in 1984, when an expensive computer might have had 1 to 10 Megabytes (!) of memory and a CPU with 8 Mhz / 1 Million instructions per second. You'll then see a bunch of different implementations, sometimes within the same running Lisp and able to use different execution modes in the same program: * source interpreted Lisp -> a Lisp Interpreter executes the code from traversing the s-expressions of the source code -> this is usually slow to execute, but there are also very convenient debug features available * compiled Lisp code -> a Lisp compiler (often incremental) compiles Lisp code to faster code: byte code for a VM, C code for a C compiler or machine code for a CPU. -> often this keeps a lot of the dynamic features * optimized compiled Lisp code -> like above, but the code may contain optimization hints (like type declarations or other annotations) -> the compiler uses this provided information or infers its own to create optimized code. For "optimized compiled Lisp code" the compiler may remove all or some of dynamic features (like late binding of functions, allowing data of generic types to be passed, runtime type checks, runtime dispatch, runtime overflow detection, removal of debug information, tail call optimization, ...). It may also inline code. The portions where such optimizations are applied span from certain parts of functions to whole programs. Common Lisp also has normal function calls and generic function calls (CLOS) -> the latter are usually a lot slower and people are experimenting with ways to make it fast (-> by removing dynamism where possible). So, speed in Common Lisp is not one thing, but a continuum. Typically one would run compiled code, where possible, and run optimized code only where necessary (-> in parts of the code). For example one could run a user interface in unoptimized very dynamic compiled code and certain numeric routines in optimized compiled code. CL-USER> (defun foo (a b) (declare (optimize (speed 3) (safety 0)) (fixnum a b)) (the fixnum (+ a (the fixnum (* b 42))))) CL-USER> (disassemble #'foo) ; disassembly for FOO ; Size: 28 bytes. Origin: #x70068A0918 ; FOO ; 18: 5C0580D2 MOVZ TMP, #42 ; 1C: 6B7D1C9B MUL R1, R1, TMP ; 20: 4A010B8B ADD R0, R0, R1 ; 24: FB031AAA MOV CSP, CFP ; 28: 5A7B40A9 LDP CFP, LR, [CFP] ; 2C: BF0300F1 CMP NULL, #0 ; 30: C0035FD6 RET NIL As you can see, with optimization instructions and type hints, the code gets compiled to tight machine code (here ARM64). Without those, the compiled code looks very different, much larger, with runtime type checks and generic arithmetic.
- pjmlp 3y agoBesides the sibling comment, Smalltalk and SELF JITs prove otherwise. Ongoing Ruby efforts as well.
- __d 3y agoAnd yet, after 30 years of effort from various different, talented people and teams, with historical knowledge of eg, StrongTalk, and Self, and Common Lisp, and Java, and JavaScript, we've yet to see any major leaps in Python performance. So, in my opinion, it's clearly not as simple as just taking all of that existing knowledge and a good team and just doing it, or one of the many efforts to do so would almost certainly have succeeded by now.