BeginInvoke的性能影响

时间:2010-03-18 20:56:15

标签: c# visual-studio-2008 .net-2.0 begininvoke

我继承了从主线程调用BeginInvoke的代码(不是后台线程,通常是模式)。我试图了解它在这种情况下的实际作用。

在BeginInvoke中调用的方法是否符合到窗口的消息?文档说asynchronously,这是我的假设。

框架如何确定何时启动BeginInvoke调用的方法?

编辑:代码如下所示:

System.Action<bool> finalizeUI = delegate(bool open)
{
    try
    {
        // do somewhat time consuming stuff
    }
    finally
    {
        Cursor.Current = Cursors.Default;
    }
};

Cursor.Current = Cursors.WaitCursor;
BeginInvoke(finalizeUI, true);

这发生在Form_Load事件中。

4 个答案:

答案 0 :(得分:4)

修改

现在我们看到了代码,很明显这只是一种将一些初始化移出Form_Load的方法,但在用户可以与表单交互之前仍然会发生这种情况。

BeginInvoke的调用在Form_load中,而不是在另一个对象上调用,因此这是对Form.BeginInvoke的调用。所以发生了什么。

  1. Form_Load将委托传递给Form.BeginInvoke,这会在表单的所有用户输入消息的提前的消息队列中放入一条消息。它将光标设置为等待光标。
  2. Form_Load返回,并允许表单初始化的其余部分完成,此时表单最有可能变为可见。
  3. 一旦代码落入消息泵,第一件事就是在队列中看到的是委托,所以它运行它。
  4. 当委托完成时,它将光标更改回正常光标,并返回
  5. 利润!
  6. 下面的原帖


    我依赖于你调用BeginInvoke的对象。如果对象派生自Control,那么Control.BeginInvoke将在创建控件的线程上运行。见JaredPar的回答。

    但是使用BeginInvoke还有另一种模式。如果对象是委托,则BeginInvoke在单独的线程上运行回调,该线程可以专门为此目的创建。

    public class Foo
    {
        ...
        public Object Bar(object arg)
        {
           // this function will run on a separate thread.
        }
    }
    
    ...
    
    // this delegate is used to Invoke Bar on Foo in separate thread, this must
    // take the same arguments and return the same value as the Bar method of Foo
    public delegate object FooBarCaller (object arg);
    
    ...
    
    // call this on the main thread to invoke Foo.Bar on a background thread
    //
    public IAsyncResult BeginFooBar(AsyncCallback callback, object arg)
    {
       Foo foo = new Foo();
       FooBarCaller caller = new FooBarCaller (foo.Bar);
       return caller.BeginInvoke (arg);
    }
    

    这种模式是从主线程而不是从后台线程调用BeginInvoke的一个原因。

答案 1 :(得分:2)

如果在UI线程上调用BeginInvoke,它仍将经历将Windows消息发布到消息将等待处理的消息队列的过程。代理将在处理消息时运行。此消息的优先级不会与从后台线程调用的方式不同。

答案 2 :(得分:1)

在这种情况下,我怀疑这个电话看起来像是:

private void Button1_Click(object sender, ButtonClickEventArgs e)
{
    Control.BeginInvoke(new MethodInvoker(()=> /* code etc. */));
}

发生的事情是某些代码将在线程池线程上运行,并更新创建控件的线程上的控件,而如果使用了Control.Invoke,某些代码将在创建控件的线程上运行,并在该线程上更新控件。

答案 3 :(得分:1)

在广泛使用BackgroundWorker之前,您必须在对UI线程上创建的控件执行任何操作之前同步回UI线程(即几乎每个控件)。

“线程安全调用Windows窗体控件”部分中有一个非常好的参考示例here