gpt4 book ai didi

c# - BeginInvoke 会阻止 UI,而 Invoke 不会。为什么?

转载 作者:太空狗 更新时间:2023-10-29 21:29:09 25 4
gpt4 key购买 nike

我对跨线程访问遇到的场景感到困惑。这是我正在尝试做的事情:

主 UI 线程 - 菜单项单击我创建一个后台工作程序并异步运行它

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

方法ExecuteTheActionSelected如下:

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

localBackgroundWorker_DoWork 有:

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

该类中的 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
}
}

UI事件处理程序如下:

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

跨线程问题来了:

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

此处 Invoke 不会在 BeginInvoke 阻塞的地方阻塞 UI。请帮助我理解这种情况,因为我很困惑。

最佳答案

是的,这是正常的。 Invoke() 的好处是它阻塞 工作线程。当您使用 BeginInvoke() 时,线程会继续运行并以高于 UI 线程可以处理的速率发出调用请求。这取决于您要求 UI 线程执行的操作,但它开始成为每秒大约 1000 次调用的问题。

在这种情况下,UI 线程停止响应,它在泵送消息循环时不断地寻找另一个调用请求,并且不再执行其常规职责。输入和绘画请求不再得到处理。

问题的明显来源是对从进程检索到的输出的每一行 的调用请求。它只是生成它们的速度太快了。您需要通过降低调用速率来解决此问题。有一个简单的规则,你只是想让一个人有事可做,每秒调用超过 25 次,无论你产生什么,但眼睛会模糊。因此缓冲行并测量自上次调用调用以来耗时量。

另请注意,使用 Invoke() 是一种简单的解决方法,但不能完全保证有效。这是一场竞赛,工作线程可能总是比主线程重新进入消息循环并读取下一条消息早一点调用下一个 Invoke()。在这种情况下,您仍然会遇到完全相同的问题。

关于c# - BeginInvoke 会阻止 UI,而 Invoke 不会。为什么?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/10497690/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com