【问题标题】:Multithreaded drawing in .NET?.NET 中的多线程绘图?
【发布时间】:2010-07-24 23:51:17
【问题描述】:

编辑:澄清一下,我的主要目标是并发,但不一定适用于多核机器

我对并发的所有概念都很陌生,但我发现我需要有并行绘图例程,原因有很多:

  • 我想分别绘制图形的不同部分(背景刷新频率低于前景,保留在缓冲区中)。
  • 我想要控制优先级(UI 响应比绘制复杂图形更优先)。
  • 我想要多线程的每帧绘图计算。
  • 我想为复杂的缓冲区绘制例程提供取消功能。

但是,作为一个初学者,我的代码很快就变得一团糟,重构或错误修复变得如此尴尬,以至于我决定在做任何严肃的事情之前我需要更多地使用它。

所以,我想知道如何编写干净、易于维护的 .NET 多线程代码,当我在第二天醒来后查看它时才有意义。我遇到的最大问题是构建应用程序,以便所有部分以一种智能(而不是笨拙和笨拙)的方式相互交流。

欢迎提出任何建议,但我更喜欢可以在空闲时间消化的资源(例如,不是 500 多页关于并发的论文)和 C#/VB.NET,直到最新版本(因为我看到有advances)。基本上,我想要一些直截了当的东西,这样我就可以开始玩我的玩具项目中的概念了。

【问题讨论】:

  • 更详细地描述您的需求将有助于人们回答您的问题。您想以多线程方式绘制整个 UI?您是否只有一个应该是多线程的控件?您可能会以消耗绘图层的线程池结束。
  • 对不起,我主要关心的是以这种并发方式构建这样的代码(通常是同步的)。在这种情况下,它是关于一个可以将其绘图拆分为两个或三个线程的单个控件,但让我难以理解的是如何将并发应用于通常在 Paint 事件上启动和完成的事物。

标签: c# vb.net multithreading concurrency parallel-processing


【解决方案1】:

但我发现我需要 并行绘图例程

三个字:NOT UNDER WINDOWS。

就这么简单。出于兼容性原因,标准 windows 绘图每个定义都是单线程的。任何 UI 控件(让我们坚持 .NET 世界)只能从它的创建线程进行操作(因此实际上它比单线程更残酷 - 它只是一个特定的线程)。

你可以单独做预先计算,但真正的绘图不必从那个线程完成。

除非你分配一个位图,在那里有你自己的绘图,然后把它交给 UI 线程来绘制到窗口上。

这与整个任务并行库等无关(我反对),而是回到一个非常古老的要求,为了简单和兼容性而保留。这就是任何 UI 线程都作为单线程公寓上市的原因。

另请注意,如果您自己实现多线程绘图,则会产生严重影响。哪一个在光学上获胜(留在前台)?使用多线程时,这并不是真正可确定的。不过,您可以随意尝试。

在这种情况下:

  • 拥有自己的缓冲区和同步是必须的。远离任何 Windows 级图形库(WPF 或 Winforms),除了最后一步(绘制位图)。

  • 据说 DirectX 11 支持多线程调用,但我不确定这能走多远。

【讨论】:

  • 我实际上在另一个线程上绘制了一个在缓冲区上绘制的例程,并使用 DrawImageUnscaled() 在 UI 线程上绘制了该缓冲区,我什至使用了 GDI+(在绘图线程上),因为它是性能还可以——我更关心的是感知性能而不是实际性能(例如,始终拥有 100% 响应式 UI,即使在绘制“背景”时也是如此,因为该缓冲区的覆盖可能使用户认为应用程序比实际响应更快,就像光标所做的那样,从不冻结)。
  • 是的,这行得通——因为对于 Windows,绘图不是来自另一个线程;)
【解决方案2】:

Task Parallel Library 绝对是寻找简化代码的地方。我亲自为Parallelism with .NET 4 写了一篇(半长的)介绍,其中涵盖了很多有用的概念。

但是请注意,您可能需要考虑让您的绘图保持单线程。您应该尽量保持计算多线程,并在 GUI 线程上完成实际的绘图操作。

大多数绘图 API 要求所有实际绘图调用发生在同一个同步上下文中。

话虽如此,使用像ConcurrentQueue 这样的新集合类可以简化这种类型的代码。尝试考虑许多线程(生产者)将“绘图操作”添加到共享的并发队列中 - 并且一个线程(消费者)获取操作并执行它们。

这为您提供了一个可扩展但相当简单的设计,您可以在此基础上进行构建。

【讨论】:

  • 呵呵,我已经在另一个标签页中打开了您介绍的一篇文章,我必须说它很棒(也是迄今为止我找到的最好的来源),我很快从中获得了洞察力。关于绘图代码,正如我所说,“背景”稍微复杂一些(它可以在缓冲区中绘制,而轻量级元素覆盖在先前的背景缓冲区上),但我面临的主要问题是在一个跨线程的优雅时尚(并在正确的时间调用渲染函数,而不是将它们放在绘制事件上)。
  • 我会继续阅读您的文章并摆弄代码,也许这比一本关于该主题的大书更有价值(满足我卑微的编码需求)。现在,+1 和无限的荣誉给你! :)
  • @Camilo:仅供参考 - 到目前为止,我在这方面看到的最好的书是 P&P 书(我是它的评论者;))。它将于下个月发布,但您可以在以下位置阅读预览:parallelpatterns.codeplex.com
  • 看起来非常好,肯定是深入研究该主题的好读物,对他们来说太糟糕了,因为您的文章几乎没有进一步介绍的空间:)
  • 我会接受你的回答,因为你的文章对我帮助很大。
猜你喜欢
  • 2012-11-19
  • 1970-01-01
  • 2013-04-21
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2011-08-13
相关资源
最近更新 更多