BeginInvoke 的性能影响

发布于 2024-08-25 21:43:56 字数 518 浏览 9 评论 0原文

我继承了从主线程(不是后台线程,这通常是模式)调用 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);

这是在 Form_Load 事件中发生的。

I've inherited code where BeginInvoke is called from the main thread (not a background thread, which is usually the pattern). I am trying to understand what it actually does in this scenario.

Does the method being called in the BeginInvoke get in line of messages that come down to the window? The docs say asynchronously, so that is my assumption.

How does the framework prioritize when to kick off the method called by BeginInvoke?

Edit: The code looks like this:

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);

This is happening in the Form_Load event.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(4

白馒头 2024-09-01 21:43:56

编辑

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

BeginInvoke 的调用位于 Form_load 内部,并且不会在其他对象上调用,因此这是对 Form.BeginInvoke 的调用。所以发生的事情是这样的。

  1. Form_Load 将委托传递给 Form.BeginInvoke,这会将消息放入表单的消息队列中,该消息位于所有用户输入消息的前面。它将光标设置为等待光标。
  2. Form_Load 返回,并且允许完成表单初始化的其余部分,此时表单很可能变得可见。
  3. 一旦代码落入消息泵,队列中首先看到的是委托,因此它会运行它。
  4. 当委托完成时,它将光标更改回正常光标,并返回
  5. 利润!

下面的原始帖子


我取决于您调用 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 的原因之一。

edit

Now that we see the code, it's clear that this is just a way to move some initialization out of Form_Load but still have it happen before the user can interact with the form.

The call to BeginInvoke is inside Form_load, and is not called on another object, so this is a call to Form.BeginInvoke. So what's happening is this.

  1. Form_Load passes a delegate to Form.BeginInvoke, this puts a message in the form's message queue that is ahead of all user input messages. It sets the cursor to a wait cursor.
  2. Form_Load returns, and the rest of form initialization is allowed to complete, the form most likely becomes visible at this point.
  3. Once the code falls into the message pump, the first thing is sees in the queue is the delegate, so it runs that.
  4. as the delegate completes, it changes the cursor back to the normal cursor, and returns
  5. profit!

original post below


I depends on the object that you call BeginInvoke on. If the object is derived from Control then Control.BeginInvoke will run on the thread that created the control. See JaredPar's answer.

But there is another pattern for the use of BeginInvoke. if the object is a delegate, then BeginInvoke runs the callback on a separate thread, one that may be created specifically for that purpose.

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);
}

This pattern is one reason that BeginInvoke is called from the main thread rather than from a background thread.

谜泪 2024-09-01 21:43:56

在 UI 线程上调用 BeginInvoke 的情况下,它仍然会经历将 Windows 消息发布到消息队列的过程,消息将在消息队列中等待处理。处理消息时委托将运行。该消息的优先级与从后台线程调用的消息不同。

In the case BeginInvoke is called on a UI thread it will still go through the process of posting a Windows Message to the message queue where the message will wait to be processed. The delegate will run when the message is processed. This message is not prioritized in any way that's different than it being called from the background thread.

毅然前行 2024-09-01 21:43:56

在这种情况下,我怀疑调用看起来像这样:

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

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

In this scenario I suspect the call looks like:

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

What's happening is that some code will run on on a threadpool thread, and update the control on the thread that created the control whereas if Control.Invoke was used, some code would run on the thread that created the control, and update the control on that thread as well.

似最初 2024-09-01 21:43:56

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

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

Prior to widespread BackgroundWorker use, you had to synchronize back to the UI thread before doing any operations on Controls created on the UI thread (i.e. pretty much every Control).

There's a pretty good reference example here down in the "Thread-Safe Calls to a Windows Forms Control" section.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文