Python vs Ruby 
Author Message
 Python vs Ruby

[Neil Schemenauer]

Quote:
> RC also works quite well with data caches and VM managers.  Using
> the Boehm-Demers GC with python and disabling reference counting
> slows the interpreter down by a significant amount.

[D-Man]

Quote:
> Really?  This is interesting.  I had thought that it would be faster.
> At the very least, the simple assignment statment can be simple.  With
> RC, both arguments' ref counts have to be checked first and then
> updated appropriately.

So consider this:

Quote:
>>> from random import choice
>>> addresses = {}
>>> letters = "abcdefghijklmnopqrstuvwxyz"
>>> for i in xrange(100000):

...     s = choice(letters) + " " + choice(letters)
...     addresses[id(s)] = 1
...

Quote:
>>> len(addresses)
9

Thanks to refcounting, the storage for "s" is reclaimed on each iteration,
and overwhelmingly most iterations manage to reuse the storage left behind
from a preceding iteration.  As Neil said, that's very cache-friendly.
Without refcounting, you're likely to stomp on new memory addresses each
iteration until some limit is reached, then gc will go lurching all over a
large blob of memory at least once (possibly more) cleaning it up.  That's
cache-hostile.

Python has extremely high dynamic memory throughput, because *nothing* is
exempted from the "everything's an object, and all objects are
heap-allocated" scheme.  Mark-&-sweep-- and especially simple M&S --is
happier with modest rates of memory turnover.

Quote:
> ...
> All the tests I've seen of the Boehm collector used C programs
> originally designed for malloc/free, not using any ref counting schemes.
> Maybe this has an effect?

No C program I know of does dynamic allocation on virtually every line.
Python programs do.  C++ is somewhere between them, but closer to the C end.

Quote:
> I wonder if python was designed for the collector instead of ref
> counting if this would improve its performance . . .

There's no sense in which Python was designed "for" ref counting.  The
single highest-payoff thing it could do here, regardless of garbage
collection scheme, would be to grow a lot of hair to *exempt* some objects
from participating in the gc scheme du jour.  For example, in a language
with more sanely static semantics, it would be easy to see in the example
above that there's no need to allocate an integer object for the result of
id(s) each time through the loop -- it could just store that result on a
stack (or in a register) and exempt it entirely from refcounting (or M&S, or
whatever).  Similarly for the loop index "i", and the function object
"choice".

BTW, note that Perl also does refcounting, and for the same reasons.  The
idea that fancier gc schemes must be faster is ... an idea <0.9 wink>.

if-anything-about-gc-seems-obvious-it's-an-illusion-ly y'rs  - tim



Sat, 19 Jul 2003 14:16:31 GMT  
 Python vs Ruby


Quote:
> [Neil Schemenauer]
> > RC also works quite well with data caches and VM managers.  Using
> > the Boehm-Demers GC with Python and disabling reference counting
> > slows the interpreter down by a significant amount.

Are you sure the collector is working correctly, and not retaining
garbage for some reason?  I looked at the source tree quickly, and it
appeared to me that the interpreter maintained a doubly linked list of
all Python objects?  That would effectively keep the collector from
reclaiming anything.  Is that list essential?

When I last looked at this 4 or 5 years ago, there were some other
issues that prevented a direct plug-in of a tracing collector.  I think
some subsystems did their own free-list management.  This tends to be a
pessimization with a tracing GC, especially if the objects on the free
list still point to other long-dead objects, etc.  I couldn't find such
issues now, but I didn't look very hard.

You can probably get a good idea whether any of these are an issue by
building the collector without -DSILENT, and looking at the amount of
reachable memory it found.
...

Quote:
> Thanks to refcounting, the storage for "s" is reclaimed on each
iteration,
> and overwhelmingly most iterations manage to reuse the storage left
behind
> from a preceding iteration.  As Neil said, that's very cache-friendly.
> Without refcounting, you're likely to stomp on new memory addresses
each
> iteration until some limit is reached, then gc will go lurching all
over a
> large blob of memory at least once (possibly more) cleaning it up.
That's
> cache-hostile.

True, although there are some tricks you can play to reduce the effect.
See http://www.hpl.hp.com/techreports/2000/HPL-2000-99.html (also in the
ISMM 2000 Proceedings).  Much of the remaining cost is that with
reference counting (or malloc/free style memory management) you often
get to allocate memory that's already in the cache.  With a M/S GC, you
usually don't.

On the other hand, reference counting is also rather cache-unfriendly,
in a different way. Assigning a reference now needs to touch both the
previously referenced and the newly referenced object, which are very
unlikely to be on the same cache line.  And both lines are dirtied, so
they will need to be written back when they are replaced.

Reference counting tends to look considerably worse if you fully support
concurrency, so that you have to update reference counts with atomic
operations.  But in my experience it rarely wins for small objects even
in the single-threaded case.  (It can win for large objects, or if you
are very tight on space, so that you would have to collect too often.)

Quote:

> Python has extremely high dynamic memory throughput, because *nothing*
is
> exempted from the "everything's an object, and all objects are
> heap-allocated" scheme.  Mark-&-sweep-- and especially simple M&S --is
> happier with modest rates of memory turnover.

I agree that reference counting looks relatively better with a high
allocation to pointer assignment ratio.  But I would also claim that
there are some high allocation rate programs for which mark/sweep is
clearly the winning strategy, e.g. if you repeatedly build a large data
structure, traverse/tweak it a few times, and then drop it.  If you
mostly allocate very short-lived objects, copying generational
collectors are hard to beat.
...

Hans

Hans_Boehm<at>hp<dot>com

Sent via Deja.com
http://www.deja.com/



Mon, 21 Jul 2003 02:53:24 GMT  
 Python vs Ruby

Quote:

> [Neil Schemenauer]
> > RC also works quite well with data caches and VM managers.  Using
> > the Boehm-Demers GC with Python and disabling reference counting
> > slows the interpreter down by a significant amount.

> Are you sure the collector is working correctly, and not retaining
> garbage for some reason?  I looked at the source tree quickly, and it
> appeared to me that the interpreter maintained a doubly linked list of
> all Python objects?  That would effectively keep the collector from
> reclaiming anything.  Is that list essential?

That linked list is only used if the cyclic garbage collector is
enabled.  It has been quite a while since I played with your GC,
before the linked list stuff was added to Python.

Quote:
> When I last looked at this 4 or 5 years ago, there were some other
> issues that prevented a direct plug-in of a tracing collector.  I think
> some subsystems did their own free-list management.  This tends to be a
> pessimization with a tracing GC, especially if the objects on the free
> list still point to other long-dead objects, etc.  I couldn't find such
> issues now, but I didn't look very hard.

Those freelists are still there.  I don't doubt that I could have
made your GC perform better.  My tests were very un-scientific
and should not be given much weight.  Mark and sweep GC will
probably be considered for Python 3000 (at least I'm going to
look at it again).

Quote:
> Reference counting tends to look considerably worse if you fully support
> concurrency, so that you have to update reference counts with atomic
> operations.

Right, that is one of the big problems with "free threading" the
current interpreter.  Currently the interpreter is protected by
one big lock.  Again, this is probably something that will be
considered in the Python 3000 design.

Thanks for your comments.

  Neil



Mon, 21 Jul 2003 18:59:55 GMT  
 
 [ 3 post ] 

 Relevant Pages 

1. Final for World Series: Python vs Ruby

2. Python vs Ruby

3. Ruby vs. Python: Decisions, Decisions

4. Ruby vs Python / Perl for Win32 Administration

5. Ruby vs. Python and Euphoria: sieve benc hmark

6. Ruby vs. Python and Euphoria: sieve benchmark

7. Python vs. Ruby (and os.path.walk)

8. Python vs. Ruby: threads - advice appreciated

9. Python vs. Ruby

10. Python Binding [Was: Re: PYTHON VS. PERL VS. TCL ]

11. ruby-python, vpython or 3D in Ruby

 

 
Powered by phpBB® Forum Software