C# BeginInvoke的性能影响

C# BeginInvoke的性能影响,c#,visual-studio-2008,.net-2.0,begininvoke,C#,Visual Studio 2008,.net 2.0,Begininvoke,我继承了从主线程(不是后台线程,通常是模式)调用BeginInvoke的代码。我试图理解它在这个场景中的实际作用 在BeginInvoke中调用的方法是否与到达窗口的消息排成一行?文档异步地说,,所以这是我的假设 框架如何确定何时启动BeginInvoke调用的方法的优先级 编辑:代码如下所示: System.Action<bool> finalizeUI = delegate(bool open) { try { // do somewhat tim

我继承了从主线程(不是后台线程,通常是模式)调用BeginInvoke的代码。我试图理解它在这个场景中的实际作用

在BeginInvoke中调用的方法是否与到达窗口的消息排成一行?文档异步地说
,所以这是我的假设

框架如何确定何时启动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);
System.Action finalizeEUI=委托(bool打开)
{
尝试
{
//做一些耗时的事情
}
最后
{
Cursor.Current=Cursors.Default;
}
};
Cursor.Current=Cursors.WaitCursor;
BeginInvoke(最终确定,正确);

这在Form_Load事件中发生。

在UI线程上调用BeginInvoke的情况下,它仍将经历将Windows消息发布到消息队列的过程,消息将在该队列中等待处理。处理消息时,代理将运行。与从后台线程调用此消息相比,此消息的优先级没有任何不同。

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

BeginInvoke
的调用在Form\u load中,没有在另一个对象上调用,因此这是对Form.BeginInvoke的调用。现在发生的是这样

  • Form_Load将委托传递给Form.BeginInvoke,这会将一条消息置于表单的消息队列中,该队列位于所有用户输入消息之前。它将光标设置为等待光标
  • Form_Load返回,并且允许表单初始化的其余部分完成,此时表单很可能变得可见
  • 一旦代码落入消息泵,队列中看到的第一件事就是委托,因此它运行委托
  • 代理完成后,它将光标更改回正常光标,并返回
  • 利润 原文如下


    我取决于你称之为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的原因之一。

    在这种情况下,我怀疑调用如下所示:

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

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

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


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

    @nobugz,我的措辞很糟糕。我试图说消息本身将位于等待处理的队列上,而不是调用方等待的队列。清除了语言,你确定吗?BeginInvoke是一条PostMessage,而不是SendMessage或SendNotifyMessage?@John,100%确定。SendMessage是同步的,不能与异步BeginInvoke一起工作,因此它使用PostMessage。您可以通过查看reflector中Control.BeginInvoke的实现来查看这一点。实际调用在MarshaledInvoke.JaredPar中:是的,SendMessage不起作用,但是SendNotifyMessage将在发布消息之前传递它,同时仍然不等待消息传递。无论如何,谢谢你的澄清。“我来看看。”约翰,很有趣。我不知道关于SendNotifyMessage的事。我从未使用过API,但我认为Send等同于synchronous,因为它几乎无处不在else@JohnKnoeller,你是说在我的场景中,BeginInvoke承担着线程上下文切换的重量吗?@AngryHacker:不,现在你已经展示了你的代码,很明显这只是JaredPar描述的一条后消息,BeginInvoke是表单上的一个方法,因此不会在单独的线程上运行委托。