On Thu, 28 Aug 2008 16:08:09 -0700, Ben Voigt [C++ MVP]
<rb*@nospam.nospamwrote:
Ok, didn't check whether that was MSIL or internalcall. Doesn't much
matter, does it?
No, not really. I just like being precise.
Posting a message to another thread waits for the next context switch,
it doesn't insert an extra context switch.
I suppose that depends on how you look at it. Calling Invoke() blocks the
calling thread, which will prematurely relinquish the current timeslice.
If you've got a CPU bound thread, with the usual 50ms timeslice, but it's
calling Invoke() every 5ms, I'd say that's adding 9 context switches for
every context switch that would have happened otherwise.
I'll acknowledge that you may have some other way of looking at it in
which you come to a different conclusion. But by my reckoning, Invoke()
does in fact wind up forcing a context switch that wouldn't otherwise
happen.
Maybe you're thinking of BeginInvoke() instead? I'd agree that that
method doesn't add context switches to the execution of the code.
Plus, DynamicInvoke is a very expensive operation.
The whole process of invoking is a very expensive operation. That
DynamicInvoke is "very expensive" isn't necessarily important.
In particular, by my measurements it doesn't look like it's expensive
enough to cause a significant difference in performance. I ran a little
test, calling Invoke() 100,000 times in a row with a do-nothing method,
once with a type of MethodInvoker and once with a type of Action.
The timing was more sensitive to which test ran first than to the actual
type. That is, the first test always was slower, regardless of which type
was being used for the call. Changing the test so that it did a "warm-up"
first, I found more consistent results showing that 100,000 calls took
about 3.3 seconds for MethodInvoker and 4.2 seconds for Action.
If I changed the test so that the method actually did something useful --
for example, setting the Text property of a control to the formatted value
of my loop index -- the execution time dropped precipitously. Almost 40
seconds in either case, a 10x slowdown.
So, yes it's faster to call MethodInvoker, but putting that into context
it means you really don't want to be calling Invoke() _either_ way too
often, assuming the delegate is actually doing to be doing something
interesting, and in any case the overhead of the call is very tiny as
compared to the cost of whatever code might actually be executed by the
delegate (10% at the most).
The documentation
(http://msdn.microsoft.com/en-us/library/zyzhdc6b.aspx) says:
The delegate can be an instance of EventHandler, in which case the
sender parameter will contain this control, and the event parameter will
contain EventArgs..::.Empty. The delegate can also be an instance of
MethodInvoker, or any other delegate that takes a void parameter list. A
call to an EventHandler or MethodInvoker delegate will be faster than a
call to another type of delegate.
Well, I can't say the documentation is wrong. My own tests prove it
correct. But that's only because the docs don't quantify how much
faster. I wouldn't call the difference significant.
Also "premature optimization" assumes that there's a cost to the
optimization. Here, there's effectively no cost at all.
Eye of the beholder. Personally, I find the newer generic delegate types
more expressive. But sure...if you don't personally see any difference
between "MethodInvoker" and "Action" semantically, the only cost involved
is that of remembering which is faster and of typing the extra
characters. Obviously neither costs is significant.
However, I still find it misleading to imply that the optimization is
worth doing. I saw no practical difference in performance, even if there
was a tiny measurable difference. No real world application is going to
find it matters which delegate type you use.
Pete