I am planning to implement a continuous-time version of a discrete-time agent-based simulation (see https://github.com/mhinsch/RRGraphs). That means there will be some sort of central scheduler that handles dispatch of actions with, both, the type of the objects and the functions to be dispatched varying dynamically. In the light of this, I thought it would make sense to invest some time to find the fastest method.
Here is some test code I wrote: https://gist.github.com/mhinsch/773b4d34012090c6c551e32ff3f2f576. Basically there are two types of agents and two types of actions where the combination of the two is determined at run-time. I expect actions to be not entirely trivial, therefore the random numbers in
step*. Part of the consideration also has to be the time it takes to line up agents and actions to be consumed by the scheduler which is why I am benchmarking the entire process not just the scheduling itself.
The results (Julia 1.1) are interesting, I think, and somewhat unexpected (for me):
static dispatch: 4.800 ms (49 allocations: 4.00 MiB) generic function, command array: 6.521 ms (34 allocations: 4.00 MiB) generic function: 8.255 ms (89454 allocations: 5.37 MiB) plain closures: 19.733 ms (189371 allocations: 4.89 MiB) typed closures: 7.245 ms (189291 allocations: 4.89 MiB) manual type check: 6.290 ms (34 allocations: 4.00 MiB) array of functors: 8.842 ms (189463 allocations: 4.89 MiB) FunctionWrapper with functor: 11.308 ms (300017 allocations: 9.63 MiB) FunctionWrapper with closure: 6.596 ms (300017 allocations: 9.63 MiB)
To sum it up, from what I have read (and tested) before I would have expected for generic function calls to perform a lot worse and FunctionWrappers with functors a lot better.
In any case, any suggestions on how to improve the code or even entirely different solutions for the problem will be gratefully received