.net 面试问题:什么时候需要Control.Invoke您使用Control.Invoke还是Control.BeginInvoke?

.net 面试问题:什么时候需要Control.Invoke您使用Control.Invoke还是Control.BeginInvoke?,.net,multithreading,invoke,invokerequired,.net,Multithreading,Invoke,Invokerequired,我最近接受了一次非常糟糕的采访,他们和你一起扮演好警察/坏警察。我的回答对他们中的一个来说都不够好,我的信心一分一分地下降。他最后一个让我困惑的问题是: 如果控件需要调用required,那么执行.Invoke或.BeginInvoke是否会有区别 让我给你举个例子,我是如何理解的: public delegate string WorkLongDelegate(int i); var del = new WorkLongDelegate(WorkLong); var callback = n

我最近接受了一次非常糟糕的采访,他们和你一起扮演好警察/坏警察。我的回答对他们中的一个来说都不够好,我的信心一分一分地下降。他最后一个让我困惑的问题是:

如果控件需要调用required,那么执行.Invoke或.BeginInvoke是否会有区别

让我给你举个例子,我是如何理解的:

public delegate string WorkLongDelegate(int i);

var del = new WorkLongDelegate(WorkLong);
var callback = new AsyncCallback(CallBack);
del.BeginInvoke(3000, callback, del);

public string WorkLong(int i)
{
      Thread.Sleep(i);
      return (string.Format("Work was done within {0} seconds.", i));            
}

private void CallBack(IAsyncResult ar)
{
    var del = (WorkLongDelegate) ar.AsyncState;
    SetText2(del.EndInvoke(ar));
}

private void SetText2(string s)
{
   if(InvokeRequired)
   {
       // What is the difference between BeginInvoke and Invoke in below?
       BeginInvoke(new MethodInvoker(() => textBox1.Text = s)); 
   }
   else
   {
       textBox1.Text = s;
   }
}
我提到BeginInvoke将异步执行,而Invoke将暂停UI线程,直到其执行。但这还不够好。尽管如此,如果使用调用,我不理解这里的性能含义。
有人能告诉我吗?

当然,如果使用asnyc版本,您的后台线程可以立即继续,而无需等待上下文切换


通常情况下,这应该比我所做的更快(对于后台线程)。

Invoke
不会停止UI线程。它阻止调用线程继续,直到UI线程完成

实际上,问题是您是否希望在UI完成更新之前继续后台操作。通常我认为是这样的——例如,如果您只是向UI提供一个进度报告,您不会因为UI线程还没有跟上进度就停止工作


另一方面,如果您需要从UI线程获取一些东西(这是非常罕见的,不可否认),那么您可能需要使用
Invoke
。我建议您应该使用
BeginInvoke
,除非您有特定的理由使用
Invoke
。但是无论哪种方式,您都应该理解其中的区别:)

Invoke()的一个非常明显的用例是当您需要调用其返回值的方法时。只有Invoke()可以为您提供,它返回对象,方法返回值

一个较弱的问题是,工作线程产生结果的速度远远快于UI线程所能跟上的速度。使用Invoke()将限制工作进程,如果没有绑定,调用列表将无法增长。然而,这仅仅是一个更大的问题的创可贴,更新用户界面的速度比人类感知的更快。每40毫秒一次,在人眼看来是平滑的。如果UI线程处理结果集合花费的时间仍然太长,您仍然希望使用Invoke()。出现此类问题的典型标志是UI线程冻结,无法对鼠标和键盘事件进行绘制和响应,因为调用请求完全淹没了它。在工作线程完成运行后,UI线程会在一段时间内保持无响应,忙于处理积压工作


另一种情况是对传递给BeginInvoke()的对象的锁定要求。使用Invoke()时不需要锁定,UI线程和工作线程不能同时访问该对象。与BeginInvoke不同,它会继续运行,如果线程继续使用同一个对象,则必须在UI线程和工作线程中使用锁来保护该对象。如果该锁定阻止工作进程取得任何进展,那么您最好使用Invoke()。这是非常罕见的,主线程开始执行委托需要花费大量时间。在调用对象后创建一个新实例总是一个好主意,这样就不需要锁定。

因此,
Invoke
容易发生死锁,具体取决于线程安全设置