为两个独立的表单设置两个GUI线程是否有意义?

时间:2010-08-27 05:15:19

标签: .net winforms multithreading user-interface invoke

在工作中,我们有一个非常耗费CPU的Windows窗体应用程序。它运行在一个24核的服务器上。

由于Windows窗体模型涉及处理消息泵的单个GUI线程,因此丰富,复杂的GUI似乎没有充分利用系统的功能。我这么说错了吗?

所以我的同事正在讨论这个问题。我们的应用恰好涉及两种或多或少的独立形式。想法让辅助表单在自己的专用线程上运行,释放应用程序的主GUI线程,只处理发送到主表单的消息。

据推测,这看起来会像这样:

void CreateAuxiliaryForm()
{
    Action displayForm = () =>
    {
        var f = new AuxiliaryForm();
        f.ShowDialog();
    };

    displayForm.BeginInvoke(displayForm.EndInvoke, null);
}

现在,首先,我不知道这样做是否安全。但我的想法是,既然这两种形式是独立的,那么每个形式都应该可以拥有自己的线程。这是真的吗?

我确实说过“或多或少”,那是因为我不能说这两种形式的没有互动。但是我的同事和我想到的是,在主表单必须以某种方式与辅助表单交互的任何场景中(比如一个处理由另一个处理的事件),我们只需要确保使用{ {1}} / Invoke将任何与GUI相关的代码发送到相应的消息泵。

人们对这个想法的看法是什么?

4 个答案:

答案 0 :(得分:4)

一般情况下:不要。

线程化UI可能有所帮助的原因很少:

  • 在用户操作
  • 之后,您正在阻止前台线程很长时间(例如> 5s)
  • 您正在阻止用户未触发的显着时间跨度(> ~300..500ms)(例如,通过定期计时器)
  • 你有非常昂贵的更新(渲染全屏图表),并期望这些表格中有十几个活跃。

否则,即使对于具有数百个按钮和控件的“来自地狱的UI”,也没有意义。

UI的唯一性能要求是它平滑,意味着用户感知 UI对其操作的响应为“即时” - 对于大多数操作来说,这是100 ... 300毫秒(取决于行动的频率和回应的“大小”。

缺点很多。 WinForms构建于Win32 GUI之上,其中线程“有点适用于顶级表单”,但需要注意才能正确使用。 Internet Explorer甚至使用特殊的进程,并且一些插件仍然设法在一个页面挂起时关闭所有选项卡。

答案 1 :(得分:3)

我最近开发了一个多形式的WinForms应用程序,它非常重视UI更新,即它大部分时间都花在表单的消息循环上,特别是在计时器和绘画操作上。个人形式本身几乎没有互相交流,因此交叉形式的UI发送不是问题。在这种情况下,我发现为每个表单运行专用的UI线程对他们的响应能力有很大的不同。

顺便说一句,我更喜欢这种模式在它自己的消息循环上启动一个表单,尽管你的方法也可以运行:

new Thread(() => Application.Run(new Form1())).Start();

答案 2 :(得分:1)

只要在各个线程上发生GUI更新(使用Control.Invoke)并且通过线程安全方式对共享状态进行任何访问,这应该没问题。

BTW,CPU密集度可能表明某些处理/计算 - 您可以在那里引入并行性。当然,这可能意味着很多变化。

答案 3 :(得分:1)

我不认为你可以在单独的线程上运行单独的表单。以我的CRT显示器为例。它以每秒70帧的最大速率刷新。这与我用于更新UI的线程数量无关;它只是普通的不能推动每秒更多的帧。你的普通电影院每秒只能以24帧的速度更新屏幕,并且仍能传达连续动画的幻觉。

只需将时间密集型处理委派给后台线程,就可以避免让一个表单干扰另一个表单上的更新。为UI创建额外的线程可能会导致额外的线程在其生命周期的大部分时间内空闲,特别是如果您不处理图形密集型应用程序。