RE: [Python-Dev] Speed up function calls
In theory, I don't see how you could improve on METH_O and METH_NOARGS. The only saving is the time for the flag test (a predictable branch). Offsetting that savings is the additional time for checking min/max args and for constructing a C call with the appropriate number of args. I suspect there is no savings here and that the timings will get worse.
I think tested a method I changed from METH_O to METH_ARGS and could not measure a difference.
Something is probably wrong with the measurements. The new call does much more work than METH_O or METH_NOARGS. Those two common and essential cases cannot be faster and are likely slower on at least some compilers and some machines. If some timing shows differently, then it is likely a mirage (falling into an unsustainable local minimum). The patch introduces range checks, an extra C function call, nine variable initializations, and two additional unpredictable branches (the case statements). The only benefit (in terms of timing) is possibly saving a tuple allocation/deallocation. That benefit only kicks in for METH_VARARGS and even then only when the tuple free list is empty. I recommend not changing ANY of the METH_O and METH_NOARGS calls. These are already close to optimal.
A beneift would be to consolidate METH_O, METH_NOARGS, and METH_VARARGS into a single case. This should make code simpler all around (IMO).
Will backwards compatibility allow those cases to be eliminated? It would be a bummer if most existing extensions could not compile with Py2.5. Also, METH_VARARGS will likely have to hang around unless a way can be found to handle more than nine arguments. This patch appears to be taking on a life of its own and is being applied more broadly than is necessary or wise. The patch is extensive and introduces a new C API that cannot be taken back later, so we ought to be careful with it. For the time being, try not to touch the existing METH_O and METH_NOARGS methods. Focus on situations that do stand a chance of being improved (such as methods with a signature like "O|O"). That being said, I really like the concept. I just worry that many of the stated benefits won't materialize: * having to keep the old versions for backwards compatibility, * being slower than METH_O and METH_NOARGS, * not handling more than nine arguments, * separating function signature info from the function itself, * the time to initialize all the argument variables to NULL, * somewhat unattractive case stmt code for building the c function call. Raymond
On Tue, 25 Jan 2005 06:42:57 -0500, Raymond Hettinger <raymond.hettinger@verizon.net> wrote:
I think tested a method I changed from METH_O to METH_ARGS and could not measure a difference.
Something is probably wrong with the measurements. The new call does much more work than METH_O or METH_NOARGS. Those two common and essential cases cannot be faster and are likely slower on at least some compilers and some machines. If some timing shows differently, then it is likely a mirage (falling into an unsustainable local minimum).
I tested w/chr() which Martin pointed out is broken in my patch. I just tested with len('') and got these results (again on opteron): # without patch neal@janus clean $ ./python ./Lib/timeit.py -v "len('')" 10 loops -> 8.11e-06 secs 100 loops -> 6.7e-05 secs 1000 loops -> 0.000635 secs 10000 loops -> 0.00733 secs 100000 loops -> 0.0634 secs 1000000 loops -> 0.652 secs raw times: 0.654 0.652 0.654 1000000 loops, best of 3: 0.652 usec per loop # with patch neal@janus src $ ./python ./Lib/timeit.py -v "len('')" 10 loops -> 9.06e-06 secs 100 loops -> 7.01e-05 secs 1000 loops -> 0.000692 secs 10000 loops -> 0.00693 secs 100000 loops -> 0.0708 secs 1000000 loops -> 0.703 secs raw times: 0.712 0.714 0.713 1000000 loops, best of 3: 0.712 usec per loop So with the patch METH_O is .06 usec slower. I'd like to discuss this later after I explain a bit more about the direction I'm headed. I agree that METH_O and METH_NOARGS are near optimal wrt to performance. But if we could have one METH_UNPACKED instead of 3 METH_*, I think that would be a win.
A beneift would be to consolidate METH_O, METH_NOARGS, and METH_VARARGS into a single case. This should make code simpler all around (IMO).
Will backwards compatibility allow those cases to be eliminated? It would be a bummer if most existing extensions could not compile with Py2.5. Also, METH_VARARGS will likely have to hang around unless a way can be found to handle more than nine arguments.
Sorry, I meant eliminated w/3.0. METH_O couldn't be eliminated, but METH_NOARGS actually could since min/max args would be initialized to 0. so #define METH_NOARGS METH_UNPACKED would work. But I'm not proposing that, unless there is consensus that it's ok.
This patch appears to be taking on a life of its own and is being applied more broadly than is necessary or wise. The patch is extensive and introduces a new C API that cannot be taken back later, so we ought to be careful with it.
I agree we should be careful. But it's all experimentation right now. The reason to modify METH_O and METH_NOARGS is verify direction and various effects. It's not necessarily meant to be integrated.
That being said, I really like the concept. I just worry that many of the stated benefits won't materialize: * having to keep the old versions for backwards compatibility, * being slower than METH_O and METH_NOARGS, * not handling more than nine arguments,
There are very few functions I've found that take more than 2 arguments. Should 9 be lower, higher? I don't have a good feel. From what I've seen, 5 may be more reasonable as far as catching 90% of the cases.
* separating function signature info from the function itself,
I haven't really seen any discussion on this point. I think Raymond pointed out this isn't really much different today with METH_NOARGS and METH_KEYWORD. METH_O too if you consider how the arg is used even though the signature is still the same.
* the time to initialize all the argument variables to NULL,
See below how this could be fixed.
* somewhat unattractive case stmt code for building the c function call.
This is the python test coverage: http://coverage.livinglogic.de/coverage/web/selectEntry.do?template=2850&entryToSelect=182530 Note that VARARGS is over 3 times as likely as METH_O or METH_NOARGS. Plus we could get rid of a couple of if statements. So far it seems there isn't any specific problems with the approach. There are simply concerns. I not sure it would be best to modify this patch over many iterations and then make one huge checkin. I also don't want to lose the changes or the results. Perhaps I should make a branch for this work? It's easy to abondon it or take only the pieces we want if it should ever see the light of day. ---- Here's some thinking out loud. Raymond mentioned about some of the warts of the current patch. In particular, all nine argument variables are initialized each time and there's a switch on the number of arguments. Ultimately, I think we can speed things up more by having 9 different op codes, ie, one for each # of arguments. CALL_FUNCTION_0, CALL_FUNCTION_1, ... (9 is still arbitrary and subject to change) Then we would have N little functions, each with the exact # of parameters. Each would still need a switch to call the C function because there may be optional parameters. Ultimately, it's possible the code would be small enough to stick it into the eval_frame loop. Each of these steps would need to be tested, but that's a possible longer term direction. There would only be an if to check if it was a C function or not. Maybe we could even get rid of this by more fixup at import time. Neal
Neal Norwitz wrote:
So far it seems there isn't any specific problems with the approach. There are simply concerns. I not sure it would be best to modify this patch over many iterations and then make one huge checkin. I also don't want to lose the changes or the results. Perhaps I should make a branch for this work? It's easy to abondon it or take only the pieces we want if it should ever see the light of day.
A branch would seem the best way to allow other people to contribute to the experiment. I'll also note that this mechanism should make it easier to write C functions which are easily used both from Python and as direct entries in a C API. Cheers, Nick. -- Nick Coghlan | ncoghlan@email.com | Brisbane, Australia --------------------------------------------------------------- http://boredomandlaziness.skystorm.net
Neal Norwitz <nnorwitz@gmail.com> writes:
* not handling more than nine arguments,
There are very few functions I've found that take more than 2 arguments. Should 9 be lower, higher? I don't have a good feel. From what I've seen, 5 may be more reasonable as far as catching 90% of the cases.
Five is probably conservative. http://mail.python.org/pipermail/python-dev/2004-February/042847.html -- KBK
Neal Norwitz wrote:
[...] This is the python test coverage: http://coverage.livinglogic.de/coverage/web/selectEntry.do?template=2850&entryToSelect=182530
This link won't work because of session management. To get the coverage info of ceval.c go to http://coverage.livinglogic.de, click on the latest run, enter "ceval" in the "Filename" field, click "Search" and click on the one line in the search result. Bye, Walter Dörwald
I agree that METH_O and METH_NOARGS are near optimal wrt to performance. But if we could have one METH_UNPACKED instead of 3 METH_*, I think that would be a win. . . . Sorry, I meant eliminated w/3.0.
So, leave METH_O and METH_NOARGS alone. They can't be dropped until 3.0 and they can't be improved speedwise.
* not handling more than nine arguments,
There are very few functions I've found that take more than 2 arguments.
It's not a matter of how few; it's a matter of imposing a new, arbitrary limit where none previously existed. This is not a positive point for the patch.
Ultimately, I think we can speed things up more by having 9 different op codes, ie, one for each # of arguments. CALL_FUNCTION_0, CALL_FUNCTION_1, ... (9 is still arbitrary and subject to change)
How is the compiler to know the arity of the target function? If I call pow(3,5), how would the compiler know that pow() can take an optional third argument which would be need to be initialized to NULL?
Then we would have N little functions, each with the exact # of parameters. Each would still need a switch to call the C function because there may be optional parameters. Ultimately, it's possible the code would be small enough to stick it into the eval_frame loop. Each of these steps would need to be tested, but that's a possible longer term direction. . . . There would only be an if to check if it was a C function or not. Maybe we could even get rid of this by more fixup at import time.
This is what I mean about the patch taking on a life of its own. It's an optimization patch that slows down METH_O and METH_NOARGS. It's a incremental change that throws away backwards compatibility. It's a simplification that introduces a bazillion new code paths. It's a simplification that can't be realized until 3.0. It's a minor change that entails new opcodes, compiler changes, and changes in all extensions that have ever been written. IOW, this patch has lost its focus (or innocence). That can be recovered by limiting the scope to improving the call time for methods with signatures like "O}O". That is an achievable goal that doesn't impact backwards compatibility, doesn't negatively impact existing near-optimal METH_O and METH_NOARGS code, doesn't mess with the compiler, doesn't introduce new opcodes, doesn't alter import logic, and doesn't muck-up existing extensions. Raymond "Until next week, keep your feet on the ground and keep reaching for the stars." -- Casey Kasem
On Wed, 26 Jan 2005 09:47:41 -0500, Raymond Hettinger <python@rcn.com> wrote:
I agree that METH_O and METH_NOARGS are near optimal wrt to performance. But if we could have one METH_UNPACKED instead of 3 METH_*, I think that would be a win. . . . Sorry, I meant eliminated w/3.0.
So, leave METH_O and METH_NOARGS alone. They can't be dropped until 3.0 and they can't be improved speedwise.
I was just trying to point out possible directions. I wasn't trying to suggest that the patch as a whole should be integrated now.
Ultimately, I think we can speed things up more by having 9 different op codes, ie, one for each # of arguments. CALL_FUNCTION_0, CALL_FUNCTION_1, ... (9 is still arbitrary and subject to change)
How is the compiler to know the arity of the target function? If I call pow(3,5), how would the compiler know that pow() can take an optional third argument which would be need to be initialized to NULL?
The compiler wouldn't know anything about pow(). It would only know that 2 arguments are passed. That would help get rid of the first switch statement. I need to think more about the NULL initialization. I may have mixed 2 separate issues.
Then we would have N little functions, each with the exact # of parameters. Each would still need a switch to call the C function because there may be optional parameters. Ultimately, it's possible the code would be small enough to stick it into the eval_frame loop. Each of these steps would need to be tested, but that's a possible longer term direction. . . . There would only be an if to check if it was a C function or not. Maybe we could even get rid of this by more fixup at import time.
This is what I mean about the patch taking on a life of its own. It's an optimization patch that slows down METH_O and METH_NOARGS. It's a incremental change that throws away backwards compatibility. It's a simplification that introduces a bazillion new code paths. It's a simplification that can't be realized until 3.0. It's a minor change that entails new opcodes, compiler changes, and changes in all extensions that have ever been written.
I really didn't want to do this now (or necessarily in 2.5). I was just trying to provide insight into future direction. This brings up another discussion about working towards 3.0. But I'll make a new thread for that. At this point, it seems there aren't many disagreements about the general idea. There is primarily a question about what is acceptable now. I will rework the patch based on Raymond's feedback and continue update the tracker. Unless if anyone disagrees, I don't see a reason to continue the remainder of this discussion on py-dev. Neal
On Wed, 26 Jan 2005 09:47:41 -0500, Raymond Hettinger <python@rcn.com> wrote:
This is what I mean about the patch taking on a life of its own. It's an optimization patch that slows down METH_O and METH_NOARGS. It's a incremental change that throws away backwards compatibility. It's a simplification that introduces a bazillion new code paths. It's a simplification that can't be realized until 3.0.
I've been thinking about how to move towards 3.0. There are many changes that are desirable and unlikely to occur prior to 3.0. But if we defer so many enhancments, the changes will be voluminous, potentially difficult to manage, and possibly error prone. There is a risk that many small warts will not be fixed, only because they fell through the cracks. I thought about making a p3k branch in CVS. It could be worked on slowly and would be the implementation of PEP 3000. However, if a branch was created all changes would need to be forward ported to it and it would need to be kept up to date. I know I wouldn't have enough time to maintain this. The benefit is that people could test the portability of their applications with 3.0 sooner rather than later. They could see if the switch to iterators created problems, or integer division, or new-style exceptions, etc. We could try to improve performance by simplifying architecture. We could see how much a problem it would be to (re)move some builtins. Any ideas how we could start to realize some benefits of Py3.0 before it arrives? I'm not sure if this is worth it, if it's premature, or if there are other ways to acheive the goal of easing transition for users and simplifying developers tasks (by spreading over a longer period of time) and reducing the possibility of not fixing warts. Neal
Neal Norwitz wrote:
On Wed, 26 Jan 2005 09:47:41 -0500, Raymond Hettinger <python@rcn.com> wrote:
[SNIP]
Any ideas how we could start to realize some benefits of Py3.0 before it arrives? I'm not sure if this is worth it, if it's premature, or if there are other ways to acheive the goal of easing transition for users and simplifying developers tasks (by spreading over a longer period of time) and reducing the possibility of not fixing warts.
The way I always imagined Python 3.0 would come about would be through preview releases. Once the final 2.x version was released and went into maintennance we would start developing Python 3.0 . During that development, when a major semantic change was checked in and seemed to work we could do a quick preview release for people to use to see if the new features up to that preview release would break their code. Any other way, though, through concurrent development, seems painful. As you mentioned, Neal, branches require merges eventually and that can be painful. I suspect people will just have to put up with a longer dev time for Python 3.0 . That longer dev time might actually be a good thing in the end. It would enable us to really develop a very stable 2.x version of Python that we all know will be in use for quite some time by old code. -Brett
Neal Norwitz
I thought about making a p3k branch in CVS
I had hoped for the core of p3k to be built for scratch so that even the most pervasive and fundamental implementation choices would be open for discussion: * Possibly write in C++. * Possibly replace bytecode with Forth style threaded code. * Possibly toss ref counting in favor of some kind of GC. * Consider ways to leverage multiple processor environments. * Consider alternative ways to implement exception handling (long jumps, etc, signals, etc.) * Look at alternate ways of building, passing, and parsing function arguments. * Use b-trees instead of dictionaries (just kidding). Raymond
Raymond> I had hoped for the core of p3k to be built for scratch ... Then we should just create a new CVS module for it (or go whole hog and try a new revision control system altogether - svn, darcs, arch, whatever). Skip
On Mon, 2005-01-31 at 00:00, Skip Montanaro wrote:
Raymond> I had hoped for the core of p3k to be built for scratch ...
Then we should just create a new CVS module for it (or go whole hog and try a new revision control system altogether - svn, darcs, arch, whatever).
I've heard rumors that SF was going to be making svn available. Anybody know more about that? I'd be +1 on moving from cvs to svn. -Barry
Barry Warsaw wrote:
I've heard rumors that SF was going to be making svn available. Anybody know more about that? I'd be +1 on moving from cvs to svn.
It was on their "things we do in 2005" list. 2005 isn't over yet... I wouldn't be surprised if it gets moved to their "things we do in 2006" list in November (just predicting from past history, without any insight). Regards, Martin
I had hoped for the core of p3k to be built for scratch [...]
Stop right there. I used to think that was a good idea too, and was hoping to do exactly that (after retirement :). However, the more I think about it, the more I believe it would be throwing away too much valuable work. Please read this article by Joel Spolsky (if you're not yet in the habit of reading "Joel on Software", you're missing something): http://joelonsoftware.com/articles/fog0000000069.html Then tell me if you still want to start over. I expect that if we do piecemeal replacement of modules rather than starting from scratch we'll be more productive sooner with less effort. After all, the Python 3000 effort shouldn't be as pervasive as the Perl 6 design -- we're not redesigning the language from scratch, we're just tweaking (albeit allowing backwards incompatibilities).
* Possibly write in C++. * Possibly replace bytecode with Forth style threaded code. * Possibly toss ref counting in favor of some kind of GC. * Consider ways to leverage multiple processor environments. * Consider alternative ways to implement exception handling (long jumps, etc, signals, etc.) * Look at alternate ways of building, passing, and parsing function arguments. * Use b-trees instead of dictionaries (just kidding).
The "just kidding" applies to the whole list, right? None of these strike me as good ideas, except for improvements to function argument passing. -- --Guido van Rossum (home page: http://www.python.org/~guido/)
On Jan 31, 2005, at 0:17, Guido van Rossum wrote:
The "just kidding" applies to the whole list, right? None of these strike me as good ideas, except for improvements to function argument passing.
Really? You see no advantage to moving to garbage collection, nor allowing Python to leverage multiple processor environments? I'd be curious to hear your reasons why not. My knowledge about garbage collection is weak, but I have read a little bit of Hans Boehm's work on garbage collection. For example, his "Memory Allocation Myths and Half Truths" presentation (http://www.hpl.hp.com/personal/Hans_Boehm/gc/myths.ps) is quite interesting. On page 25 he examines reference counting. The biggest disadvantage mentioned is that simple pointer assignments end up becoming "increment ref count" operations as well, which can "involve at least 4 potential memory references." The next page has a micro-benchmark that shows reference counting performing very poorly. Not to mention that Python has a garbage collector *anyway,* so wouldn't it make sense to get rid of the reference counting? My only argument for making Python capable of leveraging multiple processor environments is that multithreading seems to be where the big performance increases will be in the next few years. I am currently using Python for some relatively large simulations, so performance is important to me. Evan Jones
On Jan 31, 2005, at 10:43, Evan Jones wrote:
On Jan 31, 2005, at 0:17, Guido van Rossum wrote:
The "just kidding" applies to the whole list, right? None of these strike me as good ideas, except for improvements to function argument passing.
Really? You see no advantage to moving to garbage collection, nor allowing Python to leverage multiple processor environments? I'd be curious to hear your reasons why not.
My knowledge about garbage collection is weak, but I have read a little bit of Hans Boehm's work on garbage collection. For example, his "Memory Allocation Myths and Half Truths" presentation (http://www.hpl.hp.com/personal/Hans_Boehm/gc/myths.ps) is quite interesting. On page 25 he examines reference counting. The biggest disadvantage mentioned is that simple pointer assignments end up becoming "increment ref count" operations as well, which can "involve at least 4 potential memory references." The next page has a micro-benchmark that shows reference counting performing very poorly. Not to mention that Python has a garbage collector *anyway,* so wouldn't it make sense to get rid of the reference counting?
My only argument for making Python capable of leveraging multiple processor environments is that multithreading seems to be where the big performance increases will be in the next few years. I am currently using Python for some relatively large simulations, so performance is important to me.
Wouldn't it be nicer to have a facility that let you send messages between processes and manage concurrency properly instead? You'll need most of this anyway to do multithreading sanely, and the benefit to the multiple process model is that you can scale to multiple machines, not just processors. For brokering data between processes on the same machine, you can use mapped memory if you can't afford to copy it around, which gives you basically all the benefits of threads with fewer pitfalls. -bob
Bob Ippolito wrote:
Wouldn't it be nicer to have a facility that let you send messages between processes and manage concurrency properly instead? You'll need most of this anyway to do multithreading sanely, and the benefit to the multiple process model is that you can scale to multiple machines, not just processors.
yes, please!
For brokering data between processes on the same machine, you can use mapped memory if you can't afford to copy it around
this mechanism should be reasonably hidden, of course, at least for "normal use". </F>
Wouldn't it be nicer to have a facility that let you send messages between processes and manage concurrency properly instead? You'll need most of this anyway to do multithreading sanely, and the benefit to the multiple process model is that you can scale to multiple machines, not just processors. For brokering data between processes on the same machine, you can use mapped memory if you can't afford to copy it around, which gives you basically all the benefits of threads with fewer pitfalls.
I don't think this is an answered problem. There are plenty of researchers on both sides of this fence. It is not been proven at all that threads are a bad model. http://capriccio.cs.berkeley.edu/pubs/threads-hotos-2003.pdf or even http://www.python.org/~jeremy/weblog/030912.html
On Mon, 2005-01-31 at 15:16 -0500, Nathan Binkert wrote:
Wouldn't it be nicer to have a facility that let you send messages between processes and manage concurrency properly instead? You'll need most of this anyway to do multithreading sanely, and the benefit to the multiple process model is that you can scale to multiple machines, not just processors. For brokering data between processes on the same machine, you can use mapped memory if you can't afford to copy it around, which gives you basically all the benefits of threads with fewer pitfalls.
I don't think this is an answered problem. There are plenty of researchers on both sides of this fence. It is not been proven at all that threads are a bad model.
http://capriccio.cs.berkeley.edu/pubs/threads-hotos-2003.pdf or even http://www.python.org/~jeremy/weblog/030912.html
These are both threads vs events discussions (ie, threads vs an async-event handler loop). This has nearly nothing to do with multiple CPU utilisation. The real discussion for multiple CPU utilisation is threads vs processes. Once again, my knowledge of this is old and possibly out of date, but threads do not scale well on multiple CPU's because threads use shared memory between each thread. Multiple CPU hardware _can_ have physically shared memory, but it is hardware hell keeping CPU caches in sync etc. It is much easier to build a multi-CPU machine with separate memory for each CPU, and high speed communication channels between each CPU. I suspect most modern multi-CPU's use this architecture. Assuming they have the separate-memory architecture, you get much better CPU utilisation if you design your program as separate processes communicating together, not threads sharing memory. In fact, it wouldn't surprise me if most Operating Systems that support threads don't support distributing threads over multiple CPU's at all. A quick google search revealed this; http://www.heise.de/ct/english/98/13/140/ Keeping in mind the high overheads of sharing memory between CPU's, the discussion about threads at this url seems to confirm; threads with shared memory are hard to distribute over multiple CPU's. Different OS's and/or thread implementations have tried (or just outright rejected) different ways of doing it, to varying degrees of success. IMHO, the fact that QNX doesn't distribute threads speaks volumes. -- Donovan Baarda <abo@minkirri.apana.org.au> http://minkirri.apana.org.au/~abo/
On Tue, 2005-02-01 at 10:30 +1100, Donovan Baarda wrote:
On Mon, 2005-01-31 at 15:16 -0500, Nathan Binkert wrote:
Wouldn't it be nicer to have a facility that let you send messages between processes and manage concurrency properly instead? You'll need [...] A quick google search revealed this;
http://www.heise.de/ct/english/98/13/140/
Keeping in mind the high overheads of sharing memory between CPU's, the discussion about threads at this url seems to confirm; threads with shared memory are hard to distribute over multiple CPU's. Different OS's and/or thread implementations have tried (or just outright rejected) different ways of doing it, to varying degrees of success. IMHO, the fact that QNX doesn't distribute threads speaks volumes.
Sorry for replying to my reply, but I forgot the bit that brings it all back On Topic :-) The belief that the opcode granularity thread-switch driven by the GIL is the cause of Python's threads being non-distributable is only half true. Since OS's don't distribute threads well, any attempts to "Fix Python's Threading" in an attempt to make its threads distributable is a waste of time. The only thing that this might achieve would be to reduce the latency on thread switches, maybe allowing faster response to OS events like signals. However, the complexity introduced would cause more problems than it would fix, and could easily result in worse performance, not better. -- Donovan Baarda <abo@minkirri.apana.org.au> http://minkirri.apana.org.au/~abo/
Evan Jones wrote:
The next page has a micro-benchmark that shows reference counting performing very poorly. Not to mention that Python has a garbage collector *anyway,* so wouldn't it make sense to get rid of the reference counting?
It's not clear what these numbers exactly mean, but I don't believe them. With the Python GIL, the increments/decrements don't have to be atomic, which already helps in a multiprocessor system (as you don't need a buslock). The actual costs of GC occur when a collection happens - and it should always be possible to construct cases where the collection needs longer, because it has to look at so much memory. I like reference counting because of its predictability. I deliberately do data = open(filename).read() without having to worry about closing the file - just because reference counting does it for me. I guess a lot of code will break when you drop refcounting - perhaps unless an fopen failure will trigger a GC. Regards, Martin
Evan Jones <ejones@uwaterloo.ca> writes:
On Jan 31, 2005, at 0:17, Guido van Rossum wrote:
The "just kidding" applies to the whole list, right? None of these strike me as good ideas, except for improvements to function argument passing.
Really? You see no advantage to moving to garbage collection, nor allowing Python to leverage multiple processor environments? I'd be curious to hear your reasons why not.
Obviously, if one could wave a wand and make it so, we would. The argument about whether the cost (in backwards compatibility, portability, uniprocessor performace, developer time, etc) outweighs the benefit.
My knowledge about garbage collection is weak, but I have read a little bit of Hans Boehm's work on garbage collection. For example, his "Memory Allocation Myths and Half Truths" presentation (http://www.hpl.hp.com/personal/Hans_Boehm/gc/myths.ps) is quite interesting. On page 25 he examines reference counting. The biggest disadvantage mentioned is that simple pointer assignments end up becoming "increment ref count" operations as well, which can "involve at least 4 potential memory references." The next page has a micro-benchmark that shows reference counting performing very poorly.
Given the current implementations *extreme* malloc-happyness I posit that it would be more-or-less impossible to make any form of non-copying garabage collector go faster for Python that refcounting. I may be wrong, but I don't think so and I have actually thought about this a little bit :) The "non-copying" bit is important for backwards compatibility of C extensions (unless there's something I don't know).
Not to mention that Python has a garbage collector *anyway,* so wouldn't it make sense to get rid of the reference counting?
Here you're confused. Python's cycle collector depends utterly on reference counting. (And what is it with this "let's ditch refcounting and use a garbage collector" thing that people always wheel out? Refcounting *is* a form of garbage collection by most reasonable definitions, esp. when you add Python's cycle collector).
My only argument for making Python capable of leveraging multiple processor environments is that multithreading seems to be where the big performance increases will be in the next few years. I am currently using Python for some relatively large simulations, so performance is important to me.
I'm sure you're tired of hearing it, but I think processes are your friend... Cheers, mwh -- It is time-consuming to produce high-quality software. However, that should not alone be a reason to give up the high standards of Python development. -- Martin von Loewis, python-dev
participants (17)
-
"Martin v. Löwis" -
Barry Warsaw -
Bob Ippolito -
Brett C. -
Donovan Baarda -
Evan Jones -
Fredrik Lundh -
Guido van Rossum -
kbk@shore.net -
Michael Hudson -
Nathan Binkert -
Neal Norwitz -
Nick Coghlan -
Raymond Hettinger -
Raymond Hettinger -
Skip Montanaro -
Walter Dörwald