简体   繁体   English

BeginInvoke阻止了UI,而Invoke却没有。

[英]BeginInvoke is blocking the UI whereas Invoke is not.!

I am confused with scenario which I have encountered with cross thread access. 我对跨线程访问遇到的场景感到困惑。 Here is what I am trying to do: 这是我想要做的:

Main UI thread - menu item click I create a background worker and run it asynchronously 主UI线程 - 菜单项单击我创建后台工作程序并异步运行它

private void actionSubMenuItem_Click(object sender, EventArgs e)
{
       ToolStripMenuItem itemSelected = (ToolStripMenuItem)sender;
       ExecuteTheActionSelected(itemSelected.Text);
}

The method ExecuteTheActionSelected is as follows: ExecuteTheActionSelected方法如下:

private void ExecuteTheActionSelected(string actionSelected)
{
      BackgroundWorker localBackgroundWorker = new BackgroundWorker();
      localBackgroundWorker.DoWork += new DoWorkEventHandler(localBackgroundWorker_DoWork);
      localBackgroundWorker.RunWorkerAsync(SynchronizationContext.Current);
}

The localBackgroundWorker_DoWork has: localBackgroundWorker_DoWork具有:

 ActionExecutionHelper actionExecutioner = new ActionExecutionHelper()
 actionExecutioner.Execute();

The Execute method in that class that has method invoker which infact invokes the event handler in UI thread: 该类中的Execute方法具有方法调用程序,它实际上调用UI线程中的事件处理程序:

 public void Execute()
 {
      // ---- CODE -----
      new MethodInvoker(ReadStdOut).BeginInvoke(null, null);
 }

 protected virtual void ReadStdOut()
 {
      string str;
      while ((str = executionProcess.StandardOutput.ReadLine()) != null)
      {
          object sender = new object();
          DataReceivedEventArgs e = new DataReceivedEventArgs(str);
          outputDataReceived.Invoke(sender, e); 
          //This delegate invokes UI event handler
      }
 }

The UI event handler is as follows: UI事件处理程序如下:

private void executionProcess_OutputDataReceived(object sender, DataReceivedEventArgs e)
{
    if (_dwExecuteAction != null)
    {
        _dwExecuteAction.ShowDataInExecutionWindow(e.Text);
    }
}

Now here comes the cross thread issue : 现在出现了跨线程问题

public void ShowDataInExecutionWindow(string message)
{
     if (rchtxtExecutionResults.InvokeRequired)
     {
            rchtxtExecutionResults.Invoke(new ShowDataExecutionDelegate(ShowDataInExecutionWindow), message);
     }
     else
     {
            this.rchtxtExecutionResults.AppendText(message + Environment.NewLine);
     }
}

Here Invoke doesn't block the UI where as BeginInvoke blocks . 这里Invoke不会阻止作为BeginInvoke阻塞的UI Please help me understand this scenario as im confused a lot. 请帮助我理解这个场景,因为我很困惑。

Yes, this is normal. 是的,这很正常。 The benefit you get out of Invoke() is that it blocks the worker thread. 从Invoke()中获得的好处是它会阻塞工作线程。 When you use BeginInvoke() the thread keeps motoring and issues invoke requests at a rate higher than the UI thread can handle. 当您使用BeginInvoke()时,线程会保持驱动并以高于UI线程可以处理的速率发出调用请求。 It depends on what you ask the UI thread to do but it starts to become a problem around 1000 invokes per second. 这取决于你要求UI线程做什么,但它开始成为每秒1000次调用的问题。

The UI thread stops being responsive in this scenario, it is constantly finding another invoke request back while it pumps the message loop and doesn't get around doing its regular duties anymore. 在这种情况下,UI线程停止响应,它不断发现另一个调用请求,当它泵出消息循环并且不再执行其常规任务时。 Input and paint requests no longer get processed. 输入和绘制请求不再被处理。

The clear source of the problem is the invoke request on every single line of output retrieved from the process. 问题的明确来源是从进程检索的每一行输出上的调用请求。 It is just generating them too quickly. 它只是过快地产生它们。 You need to fix this by lowering the rate at which you invoke. 您需要通过降低调用率来解决此问题。 There's a simple rule for that, you are only trying to keep a human occupied, invoking more than 25 times per second turns whatever you produce in but a blur to the eye. 对此有一个简单的规则,你只是试图保持一个人的占用,每秒调用超过25次,无论你产生什么,但眼睛模糊。 So buffer the lines and measure the amount of time that has passed since the last invoke call. 因此缓冲行并测量自上次调用调用以来经过的时间量。

Also note that using Invoke() is an easy workaround but it isn't exactly guaranteed to work. 另请注意,使用Invoke()是一种简单的解决方法,但并不能保证能够正常工作。 It is a race , the worker thread could potentially always call the next Invoke() a wee bit earlier than the main thread re-entering the message loop and reading the next message. 这是一场竞赛 ,工作线程可能总是比主线程重新进入消息循环并读取下一条消息更早地调用下一个Invoke()。 In which case you will still have the exact same problem. 在这种情况下,您仍然会遇到完全相同的问题。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM