Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
290 views
in Technique[技术] by (71.8m points)

c# - Do you have to call EndInvoke (or define a callback ) for asynchronous method calls even if you don't have anything to do when it returns

I found the following code snippet on CodeProject on calling methods asynchronously at ... http://www.codeproject.com/Articles/14931/Asynchronous-Method-Invocation

private void CallFooWithOutAndRefParameters()
{
    // create the paramets to pass to the function
    string strParam1 = "Param1";
    int intValue = 100;
    ArrayList list = new ArrayList();
    list.Add("Item1");

    // create the delegate
    DelegateWithOutAndRefParameters delFoo =
      new DelegateWithOutAndRefParameters(FooWithOutAndRefParameters);

    // call the beginInvoke function!
    IAsyncResult tag =
        delFoo.BeginInvoke(strParam1,
            out intValue,
            ref list,
            null, null);

    // normally control is returned right away,
    // so you can do other work here...

    // calling end invoke notice that intValue and list are passed
    // as arguments because they might be updated within the function.
    string strResult =
        delFoo.EndInvoke(out intValue, ref list, tag);

    // write down the parameters:
    Trace.WriteLine("param1: " + strParam1);
    Trace.WriteLine("param2: " + intValue);
    Trace.WriteLine("ArrayList count: " + list.Count);
    Trace.WriteLine("return value: " + strResult);
}

There are a couple of things I don't understand about this code.

Per the comment control is returned immediately to the calling code when it hits the BeginInvoke line.

Does that mean that the code that follows (EndInvoke followed by some trace logging) only runs after the FooWithOutAndRefParameters call completes...automagically (even though that code resides in the same method). It looks a little confusing to me. (I have always used callbacks for this kind of thing.)

Using this method do I HAVE to call EndInvoke. Can I just invoke the method asyncronously and forget it happened? Any downsides to this?

If I don't call EndInvoke (as is shown in this method) should I then always have a callback? Even if the callback does nothing.

If the answers YOU SHOULD...then do you call EndInvoke OR define a callback? (The advantage to defining a callback being that you are notified of the result)

BTW I know I could check for errors or log resuls in the EndInvoke or callback (and I might in fact do that). What I was wondering is ARE THERE RISKS from not calling EndInvoke or defining a callback (memory leaks for example)? What is the best practice.

Seth

See Question&Answers more detail:os

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Reply

0 votes
by (71.8m points)

Yes, you have to call EndInvoke(). Not doing so causes a fairly nasty resource leak that lasts for 10 minutes. The underlying plumbing is .NET Remoting, 10 minutes is the, ahem, "default lifetime lease time". Do this often enough and your program will keel over. Having the delegate target take more than 10 minutes has interesting results too.

But most importantly, if not for the result of the invoked operation, you need to find out if the invoked method completed successfully. If it died on an exception then you will not find out about that until you call EndInvoke(). At which point the exception is re-raised. Actually handling that exception is fairly tricky since you don't really know how much of your program state got mutated by the delegate target before it exploded. It is pretty important that the target doesn't have too many side effects if you really want to catch it. Or conversely, that the target catches and rethrows the exception, performing state restoration as necessary.

The example you used is a pretty silly one of course, hard to come with doing anything useful between the BeginInvoke and EndInvoke calls in one method. You always rely on the callback that you can register, 2nd to last argument in the BeginInvoke call. Or in other words, don't pass null like the example code did. And favor classes like BackgroundWorker and Task, even ThreadPool.QueueUserWorkItem() to take the sting out of this code. Using a delegate's BeginInvoke() method is very low-level hacking.

Delegates are an enormously powerful abstraction in .NET but they didn't distribute its capabilities too well. Using them to implement events is boilerplate and trouble-free. Using its BeginInvoke() method properly is a black belt art. A notable detail is that it no longer works in .NETCore, support for remoting was removed from CoreCLR.


与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
OGeek|极客中国-欢迎来到极客的世界,一个免费开放的程序员编程交流平台!开放,进步,分享!让技术改变生活,让极客改变未来! Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...