2

背景: 我希望我的问题不是太含糊。我会尽量解释,不能贴太多代码,因为受影响的方法非常复杂冗长。所以我的问题是我试图加快多线程的处理速度。该应用程序用于我的 2D 游戏引擎中的照明,我在我的场景顶部绘制不同透明度级别的黑色矩形(当前导致延迟)。

对我来说,第一步是将相同亮度的相邻矩形批处理在一起,以减少一些渲染工作。结果很好(也许可以做得更好,但现在不是重点),现在我还实现了一个粗略的线程系统,它将每批一起为屏幕的单独部分照明。

我的问题的关键:在分析上述特定批处理方法的时间时(对于不同数量的线程在单独的、不相交的数据集上工作),我注意到一些奇怪的峰值。以前,当使用一个线程时,该方法执行大约需要 12ms,奇数跳转到 15ms。我没想太多。然而,当使用 2 或 3 个线程进行处理时,我得到或多或少的 4~5 毫秒,跳跃到 10 毫秒,有时甚至高达 20 毫秒。

现在我意识到,如果不检查我的代码,任何人都无法说出原因可能是什么,所以我不希望这样。相反,我试图得出一些结论,并希望现在确认它们。如前所述,每个线程都在我的数据集的一部分上工作,彼此完全不相交(它们不重叠)。但是,数据数组的入口点是通过特定类的相同实例的相同方法。所以线程都通过相同的方法访问同一个数组(但它的不同部分 - 因此我也不使用任何锁)。这会导致意外减速吗?

或者线程以这种方式运行可能是正常行为(执行时间变化超过标准的两倍)?作为另一个说明,我在需要它们的那一刻创建所有线程,并让它们运行完成。

数据集的访问方法:

public short GetLightLevelAt(int x, int y)
{
   if (inLightingBounds(x, y))
   {
      return lightData[x, y];
   }
   else
   {
      return GuessLightLevelAt(x,y); //This won't ever happen currently, guaranteed
   }
}
4

4 回答 4

2

也许您的数据集与垃圾 CPU 缓存一样大,因此性能不一致?使用多级缓存并且无法控制它,您将永远无法准确判断需要多少东西。

例如,如果您的数据与处理器上最私密的缓存大小一样大,并且您从一个线程移动到三个线程,那么您将有效地放弃它本来可以给您带来的任何性能优势。有时,一个接一个地按顺序做事真的更好。

于 2012-06-20T22:09:11.490 回答
2

在您的情况下,由于峰值很高,它可能与上面提到的垃圾收集或上下文切换有关。

但是,在同一阵列上运行多线程仍可能由于错误共享而出现速度下降。(即使有不重叠的分区)

例如,以下代码可能存在错误共享问题:

int[] array = new int[100000];
int a = 1;
int b = 0;

//The following loops run concurrently

//Thread A
for( int i = 0; i < 50000; i++ )
    array[i] = a;

//Thread B
for( int j = 50000; j < 100000; j++ )
    array[j] = b;

错误共享发生是因为 int a 和 b 被声明为彼此相邻,并且很可能彼此位于同一高速缓存行上。

如果同时运行,此代码可能根本不会出现加速,并且可能会减速。

于 2012-06-22T00:00:22.530 回答
1

您遇到的开销可能来自上下文切换或资源争用。一旦最大化可用内核,操作系统将开始上下文切换(基本上从一个进程/线程移动到另一个进程/线程)。

但是,如果不发布代码很难说。

于 2012-06-20T22:12:04.343 回答
1

您询问从几个线程切换到多个线程来运行该方法是否会导致延迟。简短的回答是否定的。

您没有锁定该数组,因此与争用无关。

GC 将随机出现在一段代码中,因此您会在这里和那里看到尖峰,而不是在特定的地方。

我敢打赌这不是一个尖峰。这是上下文切换。您的时钟分辨率很可能很高,并且您的量子尺寸也很高。所以一个单一的上下文切换会长时间停止你的线程。

如果这是您遇到麻烦的原因,那么您需要减少线程数。你让它比它可能的慢。

于 2012-06-21T01:28:42.363 回答