"Stay away from the nice doggy, children."
While reading the excellent (if somewhat late) Concurrent Programming on Windows: Architecture, Principles, and Patterns (Microsoft .Net Development) I began trying to recall the countless times that I have taken advantage of the framework's APM methods you get for free when you new up a delegate. Here's the noteworthy passage from page 418:
All delegate types, by convention, offer a BeginInvoke and EndInvoke method alongside the ordinary synchronous method. While this is a nice programming model feature, you should stay away from them wherever possible. The implementation uses remoting infrastructure that imposes a sizeable overhead...
Joe's choice of the word nice being a colloquial English word meaning not nice, shit, a poor effort. The scarcity of information from reliable sources and the arguments and proliferation of inaccuracies in the area of concurrency in .NET had me guessing that Joe's book would contain some nasty surprises which is why I'm somewhat peaved that such an important reference has only just come available, eight years after the Framework was released - and two years into my own person journey of asynchronous discovery! --grrrr.
Labels: books, concurrency, patterns, programming
3 comments:
You know, I was writing up some interview questions about this exact topic and ran across this quote from Joe. I'm wondering if it is a typo. It seems to me the implementation may use reflection rather than remoting. I can not understand why remoting would be used since that is for communication...any thoughts?
gschmitt99@gmail.com
Hi g, firstly I apologise for taking a while to publish your comment. Secondly, I hope I've not inadvertantly published your email address which is visible to me in the post body, if you didn't wish to have it public. I can't seem to edit a comment to remove it.
Regarding what you said, its something that I did wonder myself and my first thought was to reach for Reflector, followed by the thought that these methods are added by the compiler. I will endeavor to do two things: email Joe and ask, and I'll see if its possible to compile and inspect the BeginInvoke methods. An interesting side is that Remoting and Reflection won't work in a Partially Trusted context and I wonder what happens in such circumstances.
I notice from my stats that the single biggest geographic readership of this page is Redmond, and so if someone on the 'inside' can help, then please step forward.
Furthermore, whatever the outcome, I think code using this convenience would need testing to see if the workloads are too small and the benefits of concurrency are outwayed by the overhead. --I can't see a problem with kicking off a large task like this, but guidance says that the threadpool is for 'short' bursts.
The answer, or rather the technique to inspecting how it works on the inside is actually all to obvious once someone smarter than me has pointed it out.
As Joe was busy, I wrote to Stephen Toub and got not just confirmation but proof:
___ Stephen's reply ___
Hi Luke-
Joe is correct when he states that asynchronous delegate invocation uses remoting. As an example and a hint to this fact, run the following code and take a look at the call stacks output:
using System;
using System.Diagnostics;
class Program
{
static void Main(string[] args)
{
Action a = Foo;
a.BeginInvoke(ar =>
{
a.EndInvoke(ar);
Console.WriteLine("-----------------------------");
Console.WriteLine(new StackTrace().ToString());
}, null);
Console.ReadLine();
}
static void Foo()
{
Console.WriteLine("-----------------------------");
Console.WriteLine(new StackTrace().ToString());
}
}
For reference, here’s the output I see:
-----------------------------
at Program.Foo()
at System.Runtime.Remoting.Messaging.StackBuilderSink._PrivateProcessMessage(
IntPtr md, Object[] args, Object server, Int32 methodPtr, Boolean fExecuteInCont
ext, Object[]& outArgs)
at System.Runtime.Remoting.Messaging.StackBuilderSink.AsyncProcessMessage(IMe
ssage msg, IMessageSink replySink)
at System.Runtime.Remoting.Proxies.AgileAsyncWorkerItem.DoAsyncCall()
at System.Runtime.Remoting.Proxies.AgileAsyncWorkerItem.ThreadPoolCallBack(Ob
ject o)
at System.Threading.QueueUserWorkItemCallback.WaitCallback_Context(Object sta
te)
at System.Threading.ExecutionContext.Run(ExecutionContext executionContext, C
ontextCallback callback, Object state, Boolean ignoreSyncCtx)
at System.Threading.QueueUserWorkItemCallback.System.Threading.IThreadPoolWor
kItem.ExecuteWorkItem()
at System.Threading.ThreadPoolWorkQueue.Dispatch()
at System.Threading._ThreadPoolWaitCallback.PerformWaitCallback()
-----------------------------
at Program.<>c__DisplayClass1.Main>b__0(IAsyncResult ar)
at System.Runtime.Remoting.Messaging.AsyncResult.SyncProcessMessage(IMessage
msg)
at System.Runtime.Remoting.Messaging.StackBuilderSink.AsyncProcessMessage(IMe
ssage msg, IMessageSink replySink)
at System.Runtime.Remoting.Proxies.AgileAsyncWorkerItem.DoAsyncCall()
at System.Runtime.Remoting.Proxies.AgileAsyncWorkerItem.ThreadPoolCallBack(Ob
ject o)
at System.Threading.QueueUserWorkItemCallback.WaitCallback_Context(Object sta
te)
at System.Threading.ExecutionContext.Run(ExecutionContext executionContext, C
ontextCallback callback, Object state, Boolean ignoreSyncCtx)
at System.Threading.QueueUserWorkItemCallback.System.Threading.IThreadPoolWor
kItem.ExecuteWorkItem()
at System.Threading.ThreadPoolWorkQueue.Dispatch()
at System.Threading._ThreadPoolWaitCallback.PerformWaitCallback()
Hope that helps,
Stephen
Post a Comment