-->

Winforms multithreading: Is creating a new delegat

2020-06-04 09:53发布

问题:

I want to invoke a method that manipulates a control on the UI thread. My code works and I want to optimize. I am referring to this resource on MSDN.
According to there, we should do

public delegate void myDelegate(int anInteger, string aString);
//...
Label1.Invoke(new myDelegate(myMethod), new Object[] {1, "This is the string"});

Would this introduce an orphaned delegate object (a memory leak), at each call?

When I would do it with a static instance of the delegate like below and then use this instance at each call to invoke:

private static _delegateInstance = new myDelegate(myMethod);
//...
Label1.Invoke(_delegateInstance , new Object[] {1, "This is the string"});

Would this be Thread-Safe? I would it be true that this has a slightly better performance, since the delegate instance is only created once?

回答1:

Would this introduce an orphaned delegate object (a memory leak), at each call?

No it won't, it is OK.

But to avoid creating a delegate each time you could use some of the existing (if your method takes 2 string parameters and has not return):

Label1.Invoke.Invoke((Action<string, string>)myMethod, 
    new object[] { 1, "This is the string" });


回答2:

The two answers above have given some insight. There is a good article here if you want to get some more in depth information.

Both methods are thread safe, because at invoke time the thread pool allocates a thread for each call. There is the potential for locking, but if you read that article there are ways around that.

Also, you need to keep in mind that .Net handles the UI thread slightly differently. If you are dealing with WPF, you'll have to take the dispatcher into consideration. See here.

Ultimately, I'm not sure you would gain a massive performance increase with the second piece of code, so I'd be inclined to stick with the first.

N.



回答3:

An alternative "pattern" (if it can be called that) is to have the method simply invoking itself, assuming it is part of a Form class:

void myMethod(int anInteger, string aString)
{
    if (InvokeRequired)
    {
        Invoke(new Action<int,string>(myMethod),anInteger,aString);
        return;
    }

    Label1.Text = aString;
}

The Action object will stay on the heap, change the text property, then be GC'd at the next sweep. I can't see it being a performance hit unless the method holds on to some external resources, such as a handle to IE, file etc.



回答4:

First of, C# is a managed language, hence no memory leaks. Ever.

Second, Don't take MSDN as the final ruling when you're trying to optimize. Many code snippets you find there don't even hold up to MS's own coding standards (even the most basic of them) or even common sense.

Third, the line: private _delegateInstance = new myDelegate(myMetho); does not create anything static. It creates a variable which holds the new instance returned from new myDelegate(myMethod).

Last, using the "new" keyword will definitely create new myDelegate object in each call as well as a very different behavior from the second code snippet you wrote, but in some cases this is required.

You probably want to use the second option you wrote, but the real truth is that you should take the time and read\learn some more about delegates and C# in general.

Good luck and enjoy.



回答5:

Your first snippet creates a delegate object instance each time. This doesn't cause any leaks, but increases the number of objects that need to be garbage collected.

Your second snippet doesn't create the delegate objects each time, but is impossible (assuming that myMethod is an instance method) since static members cannot use instance members.

Darin Dimitrov is wrong - his code uses the existing Action delegate instead of a custom one, but it still creates a Action delegate object each time (unlike your second snippet). So, you could use the following code:

private Action<int, string> _delegateInstance = myMethod;
//...
Label1.Invoke(_delegateInstance , new Object[] {1, "This is the string"});