Optimizing multiple dispatch

Howard Stearns howard.stearns at charter.net
Sat Jun 5 23:15:17 CEST 2004


In your Multimethods, is the number of args fixed and known at the time
you first call Multimethod(), or do you need to be able to support dispatching
based on the number as well as the type of the arguments?

If the former, your __init__ method can take an n_args_to_dispatch argument,
and use this to create a function that collects the types.  For the two arg
case shown here,
   lambda args: (type(args[0]), type(args[1]))

I suppose you would save more if type_collector1(), type_collector2(), etc.
were written in C.

You could save even more if __call__ took an explict signature that you
didn't have to access from a tuple. This isn't an option for a general purpose
Multmethod, but might be ok in your domain-specific situation. Or you could have
classes Multimethod1, Multimethod2, etc.

 >>> Timer('tuple(map(type, (1, 2)))').timeit()
5.4792276672034177
 >>> Timer('(lambda args: (type(args[0]), type(args[1])))((1, 2))').timeit()
3.246841148805288
 >>> Timer('(lambda a, b: (type(a), type(b)))(1, 2)').timeit()
2.6581895185003077


Jacek Generowicz wrote:
> I have a multiple disptacher which, conceptually, looks something like
> this:
> 
> 
> 
> class Multimethod:
> 
>     def __init__(self):
>         self.methods = {}
> 
>     def __call__(self, *args):
>         return self.methods[tuple(map(type, args))](*args)
> 
>     def add_method(self, method, *types):
>         self.methods[types] = method
> 
> foo = Multimethod()
> 
> def fooii(a, b):
>     print "We got two ints"
> 
> def foosb(a, b):
>     print "We got a string and a bar"
> 
> class bar(object): pass
> 
> foo.add_method(fooii, int, int)
> foo.add_method(foosb, str, bar)
> 
> foo(1,2)
> foo("a string", bar())
> 
> 
> 
> My actual code looks nothing like this[*], because it contains a
> number of optimizations, and addresses some domain-specific
> considerations which are not relevant in this context; but the code
> shown should highlight the salient points.
> 
> Profiling suggests that "tuple(map(type, args))" is taking a
> significant proportion of time in certain critical loops.
> 
> Do you have any suggestions about how to make in run faster? (Either
> by optimizing "tuple(map(type, args)", or by using a completely
> different organization for the whole thing. There is almost certainly
> no point in addressing any other implementation detail[*] of what is
> shown here, as it is likely to be absent from my real code.)
> 
> 
> [*] For example, there is no __call__ in my implementation; it's
>     implementeted as a closure.




More information about the Python-list mailing list