尝试绘制多线程矩形
本文关键字:多线程 绘制 | 更新日期: 2023-09-27 17:57:19
我正在尝试在表单上绘制大约 3600 个点,使用一个线程非常慢,所以我决定要使用 4 个线程。
在我的代码中,我将 3600 点划分为 4 个线程,他们应该绘制它。 但是由于某种原因,ArgumentOutOfRangeException被抛出。我尝试调试我的代码,但找不到错误。
这是代码:
(忽略类_3DPoint,它只是一个具有 x,y,z 值的点。 当我绘制它们时,我只使用 x,y 值。
绘制点的代码:
public Graphics g; //g = this.CreateGraphics() in form1.Load()
public void drawrectangle(_3DPoint)
float xCord = float.Parse(p.x.ToString());
float yCord = float.Parse(p.y.ToString());
Brush b = new SolidBrush(Color.White);
xCord = lsize * xCord + center.X;
yCord = lsize * yCord + 10 + center.Y;
g.FillRectangle(b, xCord, yCord, 2, 2);
}
lsize,center只是用于按照我想要的点对齐的变量。
所有多线程操作代码:
public List<_3DPoint[]> multiThreadsdata = new List<_3DPoint[]>();
public void handlemultithread(_3DPoint[] P)
{
g.Clear(Color.Black);
for (int i = 0; i < multiThreads.Length; i++)
{
multiThreadsdata.Add(new _3DPoint[P.Length / multiThreads.Length]);
}
for (int i = 0; i < multiThreads.Length; i++)
{
for (int j = (P.Length / multiThreads.Length) * (i); j < (P.Length / multiThreads.Length) * (i + 1); j++)
{
multiThreadsdata[i][j - ((P.Length / multiThreads.Length) * i)] = new _3DPoint(P[j]);
}
}
for (int i = 0; i < multiThreads.Length; i++)
{
multiThreads[i] = new Thread(() => drawPoints(multiThreadsdata[i]));
multiThreads[i].Start();
}
}
delegate void SetCallBackPoint(_3DPoint location);
public void drawPoints(_3DPoint[] locations)
{
for (int i = 0; i < locations.Length; i++)
{
if (this.InvokeRequired)
{
SetCallBackPoint e = new SetCallBackPoint(drawrectangle);
this.Invoke(e, new object[] { locations[i] });
}
else
{
drawrectangle(locations[i]);
}
}
}
P
是一个包含所有 3600 个点的_3DPoint数组。
mutliThreads
是一个包含 4 个线程的线程 []。
我在这个for
循环的第三行handlemultithread
方法中得到异常:
for (int i = 0; i < multiThreads.Length; i++)
{
multiThreads[i] = new Thread(() => drawPoints(multiThreadsdata[i])); // <- here.
multiThreads[i].Start();
}
我不知道问题是什么,我的猜测是多线程存在一些问题,因为我只是多线程的初学者。
谢谢一堆。
当您应用注释中的建议时,完全可以在表单上快速绘制 3600 个矩形。
如果这还不够您足够的时间,您可以考虑在单个后台线程上创建 Images,将它们存储在某种缓冲区中,直到需要将它们绘制在表单Paint
事件的Graphics
对象上。只有当您可以预先知道需要在下一帧上绘制什么时,这才是可行的。
此示例使用简单的后台辅助角色用图像填充ConcurrentQueue
。代码中的注释解释了正在发生的事情。
public partial class Form1 : Form
{
static ConcurrentQueue<Image> buffer = new ConcurrentQueue<Image>();
static Random r = new Random();
public Form1()
{
InitializeComponent();
backgroundWorker1.RunWorkerAsync();
// this is already a great performance win ...
DoubleBuffered = true;
}
private void Form1_Paint(object sender, PaintEventArgs e)
{
Image img =null;
// get from buffer ..
if (!buffer.TryDequeue(out img))
{
// nothing available
// direct random
for (var x = 0; x < e.ClipRectangle.Width; x++)
{
for (var y = 0; y < e.ClipRectangle.Height; y++)
{
using (var pen = new Pen(new SolidBrush(Color.FromArgb(r.Next(255), r.Next(255), r.Next(255)))))
{
e.Graphics.DrawRectangle(pen, x, y, 1, 1);
}
}
}
}
else
{
// otherwise Draw the prepared image
e.Graphics.DrawImage(img,0,0);
Trace.WriteLine(buffer.Count);
img.Dispose();
}
}
private void button1_Click(object sender, EventArgs e)
{
// force a repaint of the Form
Invalidate();
}
private void backgroundWorker1_DoWork(object sender, DoWorkEventArgs e)
{
// as long as the form is not disposed
while (!IsDisposed)
{
// we keep 60 images in memory
if (buffer.Count < 60)
{
// bitmap
var bmp = new Bitmap(this.Width, this.Height);
var img = Graphics.FromImage(bmp);
// draw
for (int i = 0; i < 3600; i++)
{
using (var pen = new Pen(new SolidBrush(Color.FromArgb(r.Next(255), r.Next(255), r.Next(255)))))
{
img.DrawRectangle(pen, r.Next(Width),r.Next(Height), r.Next(Width), r.Next(Height));
}
}
// store the drawing in the buffer
buffer.Enqueue(bmp);
}
else
{
// simple and naive way to give other threads a bit of room
Thread.Sleep(0);
}
}
}
}
请记住,当您有一个 CPU 密集型进程时,添加更多线程不会神奇地使您的方法运行得更快。你甚至可能让情况变得更糟:更多的线程在 CPU 上竞争时间。