是否可以使用Parallel.For
循环在面板上绘图?我有一个 double 多维数组,double[][] plant
,我想并行绘制列,其中数组中的每个条目都在面板上的网格中绘制为矩形。
在使用graphahics.FillRectangle()
的线上,当我尝试时,我不断收到此错误:
An exception of type 'System.InvalidOperationException' occurred in System.Drawing.dll but was not handled in user code
Additional information: Object is currently in use elsewhere.
这是我正在使用的代码:
Parallel.For(0, simWidth, i =>
{
Color plantColor;
RectangleF plantRectangle= new Rectangle();
SolidBrush plantBrush = new SolidBrush(Color.Black);
for (int j = 0; j < simHeight; ++j)
{
int r, g = 255, b;
r = b = (int)(255 * (Math.Tanh(simulation.plants[i, j]) + 1) / 2.0);
plantColor = Color.FromArgb(100, r, g, b);
plantBrush.Color = plantColor;
plantRectangle.Location = new PointF(i * cellSize, j * cellSize);
graphics.FillRectangle(plantBrush, plantRectangle);
}
plantBrush.Dispose();
});
我认为发生的情况是图形对象无法同时处理多个调用。有没有办法解决?我尝试在每个并行调用中创建对图形对象的本地引用,但这不起作用。
最佳答案
Is it possible to draw on a panel using a Parallel.For loop?
不,没有任何实际有用的方式。
UI 对象(例如 Panel
)具有“线程关联性”。也就是说,它们由特定线程拥有,并且只能在该线程中使用。
GDI+ 对象,例如您的 Graphics
对象(您没有说明从哪里获得该对象,但人们希望它是在 PaintEventArgs
中传递给您的……如果没有,你的代码中有其他设计缺陷)可以更宽容,但不是线程安全的。您可以围绕对象的实际使用添加同步,但这些使用是缓慢的部分。序列化它们将抵消代码中并发的大部分好处。
您的问题并没有明确说明您在此处使用Parallel
是否是解决某些特定性能问题的实际尝试,而不管该问题实际上是什么。 Stack Overflow 上有许多问题及其答案,讨论了提高 Windows 窗体代码渲染性能的各种技术。
一般来说,这些技术中的大多数都涉及尽可能减少缓存完成的工作总量。根据您所显示的代码,您可能至少需要执行两件事:
- 缓存矩形和颜色的计算。每当基础参数发生变化时,您甚至可以使用
Parallel
来完成这部分计算。 - 将所有内容绘制到
Bitmap
对象中。这必须在单线程中完成,但是 a) 不必在拥有 UI 对象的 UI 线程中完成,b) 无论何时底层参数发生变化,您(再次)都可以只执行一次。绘制到Bitmap
后,您可以在发生Paint
事件时绘制Bitmap
对象,而不必重新渲染所有内容从头开始。
关于c# - Windows 窗体并行绘图,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/43289306/