6

我最近接受了一次非常糟糕的采访,他们和你一起扮演好警察/坏警察。无论我回答什么,对他们来说都不够好,我的信心每分钟都在萎缩。他最后一个让我很困惑的问题是:

如果控件需要 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;
   }
}

我提到 BeginInvoke 将异步执行此操作,而 Invoke 将暂停 UI 线程直到其执行。但这还不够好。尽管如此,如果我使用 Invoke 代替,我不明白这里的性能含义。有人可以启发我吗?

4

3 回答 3

14

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

所以实际上,问题是您是否希望在 UI 完成更新之前继续后台操作。通常我认为这种情况——例如,如果您只是向 UI 提供进度报告,您不希望仅仅因为 UI 线程还没有赶上而停止工作。

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

于 2010-10-24T17:55:20.887 回答
4

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

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

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

于 2010-10-24T18:16:21.447 回答
0

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

通常,根据我的理解,这应该更快(对于后台线程)。

于 2010-10-24T17:43:21.677 回答