我有大约40000个可能需要重新绘制的对象。 他们中的大多数不在屏幕上,所以似乎我可以通过同时进行检查来节省大量工作。但是,我的CPU使用率从未超过15%,因此它似乎仍然只使用一个核心。我是否正确实现了线程?如果是这样,为什么不使用我的所有核心?是否有更好的方法可以利用我的所有内核?
public void paintComponent(Graphics g)
{
super.paintComponent(g);
if (game.movables.size() > 10000)
{
final int size = game.drawables.size();
final Graphics gg = g;
Thread[] threads = new Thread[8];
for (int j = 0; j < 8; ++j)
{
final int n = j;
threads[j] = new Thread(new Runnable()
{
public void run()
{
Drawable drawMe;
int start = (size / 8) * n;
int end = (size / 8) * (n + 1);
if (n == 8) end = game.drawables.size(); // incase size
// % 8 != 0
for (int i = start; i < end; ++i)
{
drawMe = game.drawables.get(i);
if (drawMe.isOnScreen())
{
synchronized (gg)
{
drawMe.draw(gg);
}
}
}
}
});
threads[j].start();
}
try
{
for (int j = 0; j < 8; ++j)
threads[j].join();
}
catch (InterruptedException e)
{
// TODO Auto-generated catch block
e.printStackTrace();
}
}
else
{
for (Drawable drawMe : game.drawables)
{
if (drawMe.isOnScreen())
{
drawMe.draw(g);
}
}
}
}
答案 0 :(得分:3)
正如已经指出的那样,synchronized (gg)
正在有效地序列化所有绘图,因此由于线程创建和其他开销,您可能比单线程代码更慢。< / p>
我写的主要原因是Swing,这可能是 线程安全。所以这个程序的行为不仅可能很糟糕,而且还没有定义。
这样的线程错误在一些具有一些java运行时参数和一些图形驱动程序的机器上变成了一种棘手的行为。到过那里。做完了。不好。
JOGL将让您直接访问GPU,这是加速渲染的最可靠方法。
答案 1 :(得分:1)
要做到这一点,你可以先把每个drawMe放在一个(正确同步的)列表中,然后在连接完成后实际绘制它们。你无法加快绘图速度(尽管你已经淘汰了99%的drawMe,你已经大大减少了所需的时间),但是如果isOnScreen()
有点复杂,你会得到一些真正的工作你的核心。
ConcurrentLinkedQueue可以节省同步添加到列表的需要。
下一步可能是使用阻塞队列而不是列表,因此绘制代码可以与可见性检查并行运行。运行八次检查后,它们应该远远超出图纸。 (但我认为所有阻塞队列都需要同步或自己同步。我会跳过这个并坚持使用CLQ和第一个解决方案。更简单,也可能更快。)
并且(正如Gene指出的那样),Swing相关的一切都在EventQueue上开始。把它放在那里或生活会变得奇怪。只有您自己的代码不引用UI,才能在您的主题中运行。
答案 2 :(得分:0)
由于你还没有绘制任何屏幕外的物体,你可能会通过做你正在做的事情而获得很少的东西。
我甚至会说你让它变得更糟,但是引入速度慢的synchronize
并引入导致上下文切换的线程,这些都很昂贵。
为了提高性能,您应该考虑使用不同的绘图库,例如Java2D绘图库,它是JDK的一部分:http://java.sun.com/products/java-media/2D/index.jsp
答案 3 :(得分:-1)
我不确定java会如何处理这个问题,但是如果你像final int n
那样在范围内引用某些东西,那么其他语言将会爆炸性地死亡(因为它在循环时超出了范围)停止)。考虑将其作为可运行对象的字段。此外,在进行所有实际工作时,您正在同步图形对象。很可能你没有从中获得任何真正的性能提升。您可能会受益于显式检查对象是否并行显示在屏幕上,这是一个只读操作,将屏幕上的对象添加到其他类别的集合或集合中,然后按顺序呈现。