【问题标题】:Difference between BeginInvoke and Thread.StartBeginInvoke 和 Thread.Start 的区别
【发布时间】:2009-08-04 09:17:27
【问题描述】:

我有一个基于对话框的应用程序,我将在其中将 I/O 操作读写委托给不同的线程。

我只是想清楚这两种方法之间有什么区别..

第一种方法:(我在我的主要表单 -Form.cs 中这样做)

delegate void Action();
Action _action = new Action(Method);
this.BeginInvoke(_action);

第二种方法:

Thread th = new  Thread( new ThreadStart(_action));
th.Start();

我注意到 BeginInvoke 将 UI 挂起一秒钟,而第二种方法则没有..

请帮忙

【问题讨论】:

  • 对于信息,明确您的意思是 Control.BeginInvoke 和 Delegate.BeginInvoke 是有用的;我相信你的意思是第一个,但它们几乎完全相反,所以区别很重要。
  • 这是第一种方法(Control.BeginInvoke),因为我是在表单上这样做的。

标签: c# .net multithreading delegates


【解决方案1】:

BeginInvoke 将在与Form 相同的线程上发布消息泵的消息队列中的操作,它不会创建新线程。

Control.BeginInvoke 的行为类似于异步线程启动,但有重要的内部差异。

详细阅读文章here

【讨论】:

    【解决方案2】:

    BeginInvokes 通过向窗口发布消息,在 UI 线程上异步执行委托(这就是它挂起 UI 的原因)。如果委托中的代码访问 UI,这就是您需要做的。

    使用 Thread.Start 的方法在一个新的独立线程上执行委托。

    【讨论】:

      【解决方案3】:

      Thread.Start 在您的新 Thread 上运行它。

      Control.BeginInvoke 在 Control this 所属的线程上运行该方法。如果您当前在控件的线程上,则在您将控件返回到消息循环之前,该方法不会运行,例如退出您的事件处理程序。

      【讨论】:

        【解决方案4】:

        试试这个。

        class Form1: Form
        {
           public void ButtonWasClicked(object sender, EventArgs e)
           {
               /* Call the UI's Invoke() method */
               this.Invoke((MethodInvoker)delegate()
               {
                   /* Stuff to do.. you can access UI elements too without
                    * the nasty "Control accessed from another thread.."
                    * Use BeginInvoke() only if you have code after this section
                    * that you want the UI to execute without waiting for this 
                    * inner blockto finish. 
                    */
               });
           }
        }
        

        关于 BeginInvoke(),使用它是为了让函数立即返回并执行下一行等等,而无需等待方法完成。

        不同之处在于,如果您创建一个线程,您将可以像任何其他线程一样对其进行更多控制。您将遇到 CrossThreadExceptions!而如果您使用 IAsyncResult 和 BeginInvoke(),您将无法控制异步操作​​的执行流程,因为它由运行时管理。

        通过调用,您还可以向方法发送更多参数,并在操作完成后调用方法。

        MyDelegateWithTwoParam del = new MyDelegateWithTwoParam(_method);
        AsyncCallback callback = new AsyncCallback(_callbackMethod);
        IAsyncResult res = del.BeginInvoke(param1, param2, callback, null);
        
        private void _callbackMethod(IAsyncResult iar) {
           /* In this method you can collect data that your operation might have returned.
            * If MyDelegateWithTwoParam has a return type, you can find out here what i was. */
        }
        

        我已将两者广泛用于 UI 开发。我会更多地将线程用于类似服务的对象。 (想想一个保持并监听 TCP 连接的对象)和 UI 后面的后台工作的异步方法(也可以看看 BackgroundWorker)。 如果第一种方法需要额外的一秒钟开始,请不要担心:Thread.Abort() 不是 始终是您的最佳解决方案。在您的进程代码中尝试 _abort 标志并将其锁定。

        希望我已经回答了这个问题。

        里奥·布鲁扎尼蒂

        【讨论】:

        • 小修复:在第一个代码 sn -p 中添加:");"不带引号关闭 Invoke 方法并结束语句。
        【解决方案5】:

        正如其他人所发布的,Thread.Start 将启动一个新线程,而 Control.BeginInvoke() 将在 UI 线程上运行代码(例如,如果您想更改字段的值,则必须这样做)。

        但是,我发现在 WinForms 中执行后台任务的最简单技术是使用BackgroundWorker。你把它放到一个表单上,连接事件,然后调用 RunWorkerAsync()。然后在 DoWork 事件中编写后台任务。任何 UI 刷新都可以放在 RunWorkerCompleted 事件中。

        使用 BackgroundWorker 避免了所有烦人的线程处理和 IsInvokeRequired 的东西。

        这里有更详细的how-to article

        【讨论】:

          【解决方案6】:

          不同之处在于 BeginInvoke 方法只是在 SAME 线程上异步调用委托。

          使用 Thread.Start,您将创建一个完全不同的线程。

          Thread.Start 绝对会给您带来更好的性能!

          【讨论】:

          • 更好的性能是一个假设...并且您将遇到旧的 CrossThreadedExceptions 的线程...
          • 它是基于基本测试的假设。在此处查看快速测试:shevaspace.blogspot.com/2007/08/delegatebegininvoke-vs.html 但是是的.. 还有其他因素需要考虑,但如果您知道 CrossThreadedExceptions 并不是一个问题...
          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 2012-11-04
          • 2021-06-19
          • 1970-01-01
          • 2011-09-05
          相关资源
          最近更新 更多