4 ms·
>much faster than C++ I've been writing Python for over a decade and I find this a bit surprising (not saying you're wrong). Python's strong suit was always sp
by rectangletangle 7y ago
>much faster than C++
I've been writing Python for over a decade and I find this a bit surprising (not saying you're wrong). Python's strong suit was always speed of productivity over runtime speed IMO.
- xmprt 7y agoCould have been the C++ engineers using loads of abstractions and anti-patterns to write memory safe code at the cost of performance. Still surprising that it would be slower.
- mlthoughts2018 7y agoThe idea that Python’s strong suit is “glue code” or flexibility is a bit of a myth. Python (CPython anyway) is nothing but a special DSL for writing C programs. Any part of Python is absolutely as fast as C if you want it to be. In the projects I’m referring to, we just used Cython for this. Instead of wasting time writing in C for the whole project, managing memory allocation, building up abstractions over structs with macros, or using these things from inscrutable C++, we just wrote simple Python, used kernprof to measure places where running time actually mattered, and targeted those few small places with a Cython extension module. Since the small part of performance critical code was much simpler in Python (using pretty much zero abstraction / functions only in Cython), the compiled Cython code was faster than corresponding components of C++ implementations (that took much longer to write and understand). Most of the rest of e.g. Python standard library calls in the surrounding glue code is already C-level extension functions in Python with no measurable running time difference than C itself, and the rest of the custom Python code was measured in the profiler to be fast enough so as not to matter. The “slow” parts of Python come from the object data model and a variety of protocols like iteration, properties and MRO. But it isn’t really fair to call it “slow” because it’s a trade-off to get those features. If you need an object that supports being iterated, having its string representation overrided, and inheriting methods from some mix-in, then you are agreeing to pay a running time cost for this. If you don’t need that stuff, you could just write what you need in e.g. Cython. With more heavily automated tools now like numba, this argument for using Python as a first choice for writing very fast code is only getting more mainstream. Most of the time, you do need a bunch of “batteries included” features of Python and running time is not the resource constraint you’re worried about. And in the occasional exceptional cases when you need raw speed, you can use extension module strategies (e.g. how numpy was made) to be as fast as C.
- netfl0 7y agoExcellent summarization, my thoughts exactly!
- rectangletangle 7y agoSolid points. There are a few common patterns that tend to slow Python down though. For instance lists are dynamically allocated, so repeatedly appending to the list may cause it to reallocate. lst = [] for i in range(10_000_000): lst.append(i) Runs in ~1.67 seconds on my system, using 3.7 (this behavior is also generally true for older versions like Python 2). However due to the leaky abstraction, you can force allocation all at once which speeds things up, albeit at the loss of clarity. length = 10_000_000 lst = [None] * length for i in range(length): lst[i] = i Runs in ~1.21 seconds. However in these trivial cases Python offers more idiomatic approaches, which also perform better. lst = [i for i in range(10_000_000)] Runs in ~0.44 seconds. lst = list(range(10_000_000)) Runs in ~0.22 seconds. Strings behave similarly when comparing the join method to incremental appending. string = '' for _ in range(10_000_000): string += 'a' Is slower than the more idiomatic join/comprehension. string = ''.join('a' for _ in range(10_000_000)) Or even more concisely: string = 'a' * 10_000_000 Still the trade-off is worth the versatility most of the time IMO. And like you pointed out you can always drop down to C if necessary.