面试问题:当Control.InvokeRequired使用Control.Invoke或Control.BeginInvoke时?

Hou*_*man 6 .net multithreading invoke invokerequired

我最近有一次非常糟糕的采访,他们会和你一起打好警察/坏警察.无论我回答什么,对他们中的一个人来说都不够好,我的信心也在逐渐缩小.他真正困惑我的最后一个问题如下:

如果控件需要InvokeRequired,那么.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;
   }
}
Run Code Online (Sandbox Code Playgroud)

我提到BeginInvoke会以异步方式执行它,而Invoke会暂停UI线程直到执行它.但这还不够好.尽管如此,如果我使用Invoke,我不明白这里的性能含义.愿有人请赐教吗?

Jon*_*eet 15

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

实际上,问题是您是否希望在UI完成更新之前继续后台操作.通常我认为情况就是这样 - 例如,如果你只是向UI提供进度报告,你不想因为UI线程尚未赶上而停止工作.

另一方面,如果你需要从UI线程中获取某些东西(这是非常罕见的,不可否认),那么你可能想要使用Invoke.我会说你应该使用,BeginInvoke除非你有特定的理由使用Invoke.但无论哪种方式,你应该了解差异:)

  • 因此,"Invoke"易受死锁攻击,具体取决于您的线程安全设置 (2认同)

Han*_*ant 5

Invoke()的一个非常明显的用例是当你需要调用一个你需要它的返回值的方法时.只有Invoke()可以为您提供此功能,它返回Object,方法返回值.

较弱的一个是工作线程产生结果的速度远远快于UI线程可以跟上的速度.使用Invoke()将限制工作程序,并且调用列表无法无限制地增长.然而,这仅仅是一个更大问题的创可贴,没有任何人能够感知到的更新UI是没有意义的.每40毫秒一次,人眼看起来很光滑.如果UI线程仍需要太多时间来处理结果集合,您仍然希望使用Invoke().像这样的问题的经典迹象是UI线程冻结,没有绕过绘画和响应鼠标和键盘事件,因为它完全被调用请求所淹没.在工作人员完成运行后,UI线程在一段时间内没有响应,忙于处理积压工作.

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