当使用并行时,BeginInvoke是工作的,而Invoke不是——c# 4.0
本文关键字:Invoke 不是 工作 并行 BeginInvoke | 更新日期: 2023-09-27 18:10:11
当我在AddListBoxItem函数内使用invoke时,如下所示软件变得无响应和冻结,但如果我使用BeginInvoke它工作。为什么会这样?
visual studio 2010, c# 4.0
private void button2_Click(object sender, EventArgs e)
{
var watch = Stopwatch.StartNew();
Parallel.For(2, 20, (i) =>
{
var result = SumRootN(i);
AddListBoxItem("root " + i + " : " + result);
});
AddListBoxItem(watch.ElapsedMilliseconds.ToString());
}
private delegate void AddListBoxItemDelegate(object item);
private void AddListBoxItem(object item)
{
if (this.listBox1.InvokeRequired)
{
this.listBox1.Invoke(new AddListBoxItemDelegate(this.AddListBoxItem), item);
}
else
{
this.listBox1.Items.Add(item);
}
}
UI线程将等待Parallel.For
完成后再继续。这意味着它不能处理任何进一步的UI消息,直到它完成。
现在,当工作线程调用Invoke
,他们等待直到UI线程处理委托之前,他们继续。所以他们在等待UI线程获得自由,基本上。
因此,你有一个死锁——UI线程正在等待任务,任务正在等待UI线程…BeginInvoke
工作是因为任务线程不等待委托在UI线程中被处理。
我建议你不要在UI线程中调用Parallel.For
。你将阻塞UI直到它完成,这不是一个好主意。在后台线程中完成所有的事情-然后你仍然可以使用Invoke
,如果你想,当它在做计算时,UI仍然会响应。
听起来像是UI线程死锁。这很有意义,因为button2_Click
在For
完成之前不会退出,特别是,在button2_Click
完成之前不能处理任何消息循环事件。如果您在不同的线程上,Invoke
使用一个消息循环事件,并且在该项目被处理之前不会返回-因此什么都不会做-并且For
/button2_Click
将永远不会完成。
BeginInvoke
,您只需队列此工作- BeginInvoke
立即返回。这意味着For
可以完成,这让button2_Click
完成,然后允许处理消息循环事件(更新UI)。
我认为这是因为主线程被阻塞在上面的点击事件,等待完成AddListBoxItem,这是等待butttion2_click事件返回。
你不应该在你的UI中有控制器逻辑,所以Click没有在不同线程中调用逻辑的主要问题。
在为你的逻辑实现一个线程之后,你的GUI不会阻塞,并且在任何情况下都可以轻松刷新。