8 ms·
Guido van Rossum's Performance tips for Python
- rjh29 14y agoProgrammers should not be forced to sacrifice flexibility from using function calls, objects or getters/setters in order to speed up a program. The performance hit from those things should either be miniscule or optimised away by the compiler as appropriate.
- shin_lao 14y agoFeel free to create your language...
- grifaton 14y agoSounds like you're looking for a Sufficiently Smart Compiler[0]. James Hague has a good piece on why this might not be so desirable[1]. One of the reasons I'm fond of Python is that, while there is a tradeoff between flexibility and performance, it gives you the means to sacrifice flexibility to aid you in improving performance -- once you've identified what (if any) actual performance bottlenecks you face. [0] http://c2.com/cgi/wiki?SufficientlySmartCompiler http://c2.com/cgi/wiki?SufficientlySmartCompiler [1] http://prog21.dadgum.com/40.html http://prog21.dadgum.com/40.html
- rjh29 14y agoWell, there's PyPy, which is on average 5.7 times faster than CPython. So these optimisations are definitely possible, not hypothetical.
- apendleton 14y agoActually, my experience with PyPy, while generally positive, has exhibited many of the characteristics that article talks about in terms of downsides to "sufficiently-smart compilers." It's almost always much faster than cpython, but how much faster is highly variable, and not especially predictably so; seemingly-insignificant changes can have large and unexpected performance implications, and it's difficult as a developer to have the proper mental model to figure out what's actually going on. In CPython land, Python is slower, but performs predictably, and if you want to speed it up you write C, which is much faster, and also performs predictably, though it takes some developer effort. In PyPy, you get some of the speed of C without the effort, but without the predictability either.
- jrockway 14y agoC is also unpredictable: see the article from a couple days ago entitled "Why does my function run faster when the input array is sorted?" (The answer was: branch prediction.)
- to3m 14y agoI'm not sure that counts in the same way. You would have the branch prediction issue even if you program in assembly language and have precise control over the instructions the computer executes.
- Peaker 14y agoOptimizing away getter/setter calls and function call overhead in general is well within the reach of current compilers.
- tjgq 14y agoIn general, function calls cannot be inlined by the Python compiler because (almost) any function name may be re-bound to a different object at run time. A very smart compiler could probably attempt to prove that no such modification can occur at run time throughout the whole program; but this is much harder than simply deciding whether inlining a given call is worth it or not.
- cma 14y agoV8 handles them w minimal overhead in JavaScript.
- pjscott 14y agoAnd more to the point, PyPy can do Python inlining with its tracing JIT. The method, in both cases, is similar: find some type assumptions that are useful and usually true, generate code under those assumptions, and fall back on more generic code if they're ever false.
- dmorgan 14y ago>Sounds like you're looking for a Sufficiently Smart Compiler[0]. James Hague has a good piece on why this might not be so desirable[1]. So, sounds like he's looking for something like v8. if v8 can be 10-30 times faster than Python, for an equal or even more dynamic language, I don't see why Python should need to manual tune the things Guido describes in order to get some speed.
- famousactress 14y agoThis is too black and white. Don't fret, you can use function calls all you want in python... the situations in which Guido is talking about being conscious of your stack frame are pretty rare in typical practice. Also, getters/setters are totally inane in python (and probably most other languages). In fact, in general Guido's advice reads as a good warning to folks showing up from other languages who's first reaction might be to create a com/mycubiclefarm/exceptions/abstract/ directory and start writing SeriousBaseClassesForMyExceptions.
- ExpiredLink 14y ago>> creating a stack frame is expensive. > the situations in which Guido is talking about being conscious of your stack frame are pretty rare in typical practice Excessive function calls in tight loops may be expensive but hardly stack frames.
- axiak 14y agoI don't know how much experience you have with python.. but you don't need getters/setters in order to gain flexibility. You can always redefine how assignment/accessing works for any property later.
- ntoshev 14y agoEven in Java you don't need the trivial getters/setters anymore. Everyone uses an IDE with refactoring capabilities, so the change can be done instantly when necessary. Why uglify your code in advance?
- axiak 14y agoOf course it depends on who's using your code. In java, if you have an api that other people are using, then you must use getters and setters. In python there is no such restriction.
- rjh29 14y agoNot much, so I will ask a question. What's more pythonic - avoiding getters/setters, or having assignment do more than simple assignment without the caller knowing about it? Or does the issue simply not come up in practice, because you rarely need to redefine how assignment/accessing works?
- olavk 14y agoIf you are writing very performance critical code, you shouldn't write in Python anyway. You chose Python because ease of development is more important than raw performance. The overhead of function calls and property access in Python is part of the price for the increased flexibility of the language. Rossums tips are for the corner case where you want to improve performance but you don't bother rewriting in C, e.g. if you have a small bottleneck in a larger program.
- SoftwareMaven 14y agoThere are few applications that require 100% of the code to be high performance. Most performance problems are of the "bottleneck" kind, so writing your entire app in a language like Python for that ease of development is smart. It gives you options to optimize that 1-2% of your code that is critical without incurring a development penalty on the other 98-99%. GVR's tips can be seen as an escalation path for optimizing. Don't jump into C before you've actually optimized your Python, because you might not need to. In 10 years of writing Python, I've yet to hit a point where I've needed to do that. I'm kind of looking forward to it, actually.
- scott_s 14y agoSacrificing abstractions is quite common in all languages when optimizing code.
- jasomill 14y agoFor what it's worth, the only thing you sacrifice in Python by omitting trivial a getter/setter pair is the docstring: unlike Java, the syntax doesn't change, and, for Python classes, there is no such thing as .NET-style "binary compatibility".
- dbaupp 14y agoAnother good one is: use PyPy (assuming that it supports your code).
- freyrs3 14y agoNumba and Cython are also worth mentioning if you're doing numeric programming.
- pjscott 14y agoCython is definitely worth learning if you're writing in Python and want to make something that runs fast -- numeric or otherwise. It's a Python-to-C compiler that has two killer features: 1. For the most part, you can just take existing Python code and have it magically transformed into not-too-horrible C. A few optional type annotations will help with the speed, but the compatibility is great right from the get-go. 2. With a little care, you can often get the inner loops of your Python code to be just as fast as hand-written C. The tutorial is a quick read, and gets you up to speed without much effort: http://docs.cython.org/ http://docs.cython.org/
- Xion 14y agoPython code optimization is actually tricky ground where analogies from other languages (like C/C++) don't necessarily apply. One of the more surprising results (esp. for non-pythonists) is the fact that string formatting: s = "%s" % some_integer is faster than "casting" to string: s = str(some_intenger) That's solely because looking up the 'str' symbol requires finding an element in global symbols' hashtable. This turns out to be more expensive than parsing the format string and building the result of % operator.
- fauigerzigerk 14y agoApparently there's a function call overhead as well that the % operator doesn't incur because for i in xrange(10000000): s = "%s" % i is also faster than lstr = str for i in xrange(10000000): s = lstr(i) [Edit] After thinking about it a second longer, I wonder whether there is some lookup for lstr as well even though it's local. But storing the function in lstr is faster than using str so I'm not sure how this is actually implemented. I'm sure someone here will know more.
- njharman 14y agoYes there is lookup, always lookup. Dynamic language, something in loop could change what lstr is. Each "dot" incurs lookup. Your example reminds me of one idiom. Assigning nested.look.up to local var for access inside loop.
- dmorgan 14y ago>Yes there is lookup, always lookup. Dynamic language, something in loop could change what lstr is. And why is that presented as something inevitable? The interpreter/compiler could analyze that part and see that the function/name is not changed during the loop, and cache for that. I'd guess that PyPy tries to do it that way, anyway...
- lvh 14y agoYes, that's one of the many optimizations PyPy does, however it's only a very limited one. PyPy goes much, much deeper than this, with tools like function inlining and escape analysis.
- Nursie 14y agoDon't assume that threads will be useful, in CPython they are simply an abstraction and don't actually run in parallel. To make use of a multi core system you need to use processes. I'd still like it if they could get rid of the GIL...
- dbaupp 14y agoThey aren't entirely a non-parallel abstraction. C extension modules can release the GIL[1] and continue calculating. A notable example of this is Numpy/Scipy[2]. [1]: http://docs.python.org/c-api/init.html#thread-state-and-the-global-interpreter-lock http://docs.python.org/c-api/init.html#thread-state-and-the-... [2]: http://www.scipy.org/ParallelProgramming#head-9e56edb190bf1ef0863981dcaf22371e1ae8bc7b http://www.scipy.org/ParallelProgramming#head-9e56edb190bf1e...
- Nursie 14y agoTrue, there are options, I guess I was just referring to straight python threads and interpreter calls, not what you can do with extensions. For heavy math workloads, which was what I was thinking of, you can use the techniques you linked to there to great effect. It is something that you need to put a little more thought into than you might in a non-locked situation like pthreads in C though.
- andrewcooke 14y agoalso multiprocessing. but i suspect you were voted down because these days hn favours tribal groupthink (you criticised python) over rational thought.
- d0mine 14y agoGIL or no GIL, threads run concurrently in Python. The difference might be in performance: - IO-bound tasks: GIL is released - CPU-bound tasks on N-core on a single host. To exploit multiple CPUs: a) no GIL (hypothetical): N times speed up (optimistically) (it suggests weak data dependency i.e., multiprocessing can be used to the same effect) b) option a) with multiple processes (shared memory or communication-based approach) Code complexity is the same on average (except on Windows) c) C extensions (existing or new): speed up 10*N or more on numerical code Cython makes it easy to write new extensions. Currently due to dynamic nature of Python, GIL or no GIL, C extensions might be necessary to exploit hardware fully (though C extensions might not be an option in some projects) - scalable to multiple hosts tasks: different processes i.e., GIL is not a problem Benefits of GIL: - C extensions (and the interpreter) are simpler to write correctly. Multithreaded programming is not trivial we need all the help we can get. - no performance penalty for single-threaded code - it encourages a synchronization through communication concurrent model (builtin in Go) Disadvantages: - some applications have no localized performance bottlenecks. So writing a small C extension won't help to get possible performance benefits of running on multicore in parallel. If performance is critical; Python might not be the right tool in this case - there are pathological cases when performance suffers greatly due to GIL (though other approaches would have their own pathological cases) - a (non-informed) perception that Python can't benefit from multicore
- avallark 14y agoI would just say: 1. Use built in data structures whenever possible 2. First fix your process flow, then spend more time to fix your code. Doing steps A C E F B and D might be better than A B C D E F. 3. Write direct queries with db when all else fails.
- stefantalpalaru 14y ago"The universal speed-up is rewriting small bits of code in C" - pretty much sums up the subject of Python performance. Even in Cython you have a Python dialect that's translated to C.
- fox91 14y agoBe aware, a lot of Python tips for improving performance are releated to the Python implementation you're using. We should remark a clear distinction between Python tips and CPython tips. In PyPy or other implementations some tips does just not make sense and are useless (e.g.: local scope stuff vs. outer scope stuff in loops).
- deleted 14y ago[deleted]
- fijal 14y agoThis is, sadly, completely opposite to what we try to advocate with PyPy, which is you should not sacrifice your abstractions in favor of performance and you should not need to rewrite in C, barring few corner cases, like writing kernels. Surprisingly enough, I happen to have a talk when I discuss this precise topic, for people with a 30min to kill. http://www.youtube.com/watch?v=ZHF5Aius_Qs&feature=youtu.be http://www.youtube.com/watch?v=ZHF5Aius_Qs&feature=youtu...
- zobzu 14y agoPypy, you mean the people who dont see value in properly supporting HTTPS when retrieving packages?
- JeremyBanks 14y agoWe're talking about PyPy: http://pypy.org/ http://pypy.org/ You seem to be talking about PyPi: http://pypi.python.org/ http://pypi.python.org/
- RegEx 14y agoI personally was confused by this for a decent amount of time.
- someperson 14y agoNow we need a "PiPy" (I suggest it simply be python implementation of the algorithm to calculate decimal places in pi) and PiPi (not idea what it would do). (Sorry about fluff comment, couldn't resist. We digress.)
- deleted 14y ago[deleted]
- deleted 14y ago[deleted]
- 14y ago
- thedeuce 14y agoPATTERN NUMBER ONE: DON'T USE PYTHON IF YOU NEED PERFORMANCE
- zobzu 14y agoIt's missing one tip I like: Make sure your functions are calling CPython functions for heavy operations, specially when using libraries. I often use python libs which functions are written in python itself and create bootlenecks. Rewrite those functions by calling "native" CPython functions, generally make an extremely large differences
- markmm 14y agoUse C, Python is a scripting language.
- CJefferson 14y agoThis is one advantage of C++ (and C, and others) which I didn't really realise until fairly recently. Because I have a good quality compiler, I do not have to worry about little functions. If I want to make a class with a single int member, and a bunch of member functions, I can trust that will, in most cases, compile away to be just as efficient as a raw int and inline code. It is very liberating to not have to worry about the efficiency of creating another function.