【问题标题】:Parallelism vs Threading - Performance并行与线程 - 性能
【发布时间】:2015-03-19 08:42:22
【问题描述】:

我一直在阅读有关该主题的内容,但我无法找到我的问题的具体答案。我对使用并行/多线程来提高我的游戏性能很感兴趣,但我听到了一些相互矛盾的事实。例如,多线程可能不会对游戏的执行速度产生任何改进。我

我想到了两种方法:

  • 将渲染组件放入线程中。有一些事情 我需要改变,但我很清楚需要改变什么 完成。
  • 使用 openMP 并行化渲染功能。我已经编写了代码,因此这可能是更简单的选择。

这是一个 Uni 评估,目标硬件是我 Uni 的计算机,它们是多核(4 核),因此我希望使用其中任何一种技术来实现一些额外的效率。

因此,我的问题如下:我应该更喜欢哪一个?哪个通常会产生最好的结果?

编辑:我的意思是并行化/多线程的主要功能:

void Visualization::ClipTransBlit ( int id, Vector2i spritePosition, FrameData frame, View *view )
{
    const Rectangle viewRect = view->GetRect ();
    BYTE *bufferPtr = view->GetBuffer ();

    Texture *txt = txtMan_.GetTexture ( id );
    Rectangle clippingRect = Rectangle ( 0, frame.frameSize.x, 0, frame.frameSize.y );

    clippingRect.Translate ( spritePosition );
    clippingRect.ClipTo ( viewRect );
    Vector2i negPos ( -spritePosition.x, -spritePosition.y );
    clippingRect.Translate ( negPos );

    if ( spritePosition.x < viewRect.left_ ) { spritePosition.x = viewRect.left_; }
    if ( spritePosition.y < viewRect.top_ ) { spritePosition.y = viewRect.top_; }

    if (clippingRect.GetArea() == 0) { return; }

    //clippingRect.Translate ( frameData );

    BYTE *destPtr = bufferPtr + ((abs(spritePosition.x) - abs(viewRect.left_)) + (abs(spritePosition.y) - abs(viewRect.top_)) * viewRect.Width()) * 4; // corner position of the sprite (top left corner)
    BYTE *tempSPtr = txt->GetData() + (clippingRect.left_ + clippingRect.top_ * txt->GetSize().x) * 4;

    int w = clippingRect.Width();
    int h = clippingRect.Height();
    int endOfLine = (viewRect.Width() - w) * 4;
    int endOfSourceLine = (txt->GetSize().x - w) * 4;

    for (int i = 0; i < h; i++)
    {
        for (int j = 0; j < w; j++)
        {
            if (tempSPtr[3] != 0)
            {
                memcpy(destPtr, tempSPtr, 4);
            }

            destPtr += 4;
            tempSPtr += 4;
        }

        destPtr += endOfLine;
        tempSPtr += endOfSourceLine;
    }

}

【问题讨论】:

  • 你能发布你正在考虑多线程的代码吗?
  • 最佳结果取决于各部分的可并行性,以及您梳理并行性以便加以利用的能力。不调查代码就无法回答问题。
  • @MichaelB。它有点长,因为它包含多个功能,但如果有必要我会做一个 pastebin 链接。
  • 感觉这个问题太笼统了。
  • @inetknght 我担心可能是这种情况。如果是这样,请随时投票关闭它。

标签: c++ multithreading optimization parallel-processing


【解决方案1】:

不要为每个像素调用 memcpy,而是考虑在此处设置值。多次调用函数的开销可能会主导此循环的整体执行时间。例如:

for (int i = 0; i < h; i++)
{
    for (int j = 0; j < w; j++)
    {
        if (tempSPtr[3] != 0)
        {
            *((DWORD*)destPtr) = *((DWORD*)tempSPtr);
        }

        destPtr += 4;
        tempSPtr += 4;
    }

    destPtr += endOfLine;
    tempSPtr += endOfSourceLine;
}

您还可以通过使用这里提到的技巧之一avoiding conditionals 来避免条件 - 在如此紧密的循环中,条件可能非常昂贵。

编辑 - 至于是同时运行多个 ClipTransBlit 实例还是在内部并行化 ClipTransBlit 更好,我想说一般来说最好在尽可能高的水平上实现并行化,以减少通过设置它产生的开销(创建线程,同步等等)

在您的情况下,因为看起来您正在绘制精灵,如果它们重叠,那么如果没有额外的同步,您的高级线程可能会导致令人讨厌的视觉伪影,甚至在检查 alpha 位时出现竞争条件。在这种情况下,低级并行可能是更好的选择。

【讨论】:

  • 我看不出有任何方法可以在每行调用一次而不做其他会降低性能的事情。另外,这是渲染,我处理图形的唯一其他时间是在将视图缓冲区写入屏幕时。
  • @MKII 我没有注意到您只是在 alpha 字节不为零时才写入 dest - 您可能仍会从删除对 memcpy 的调用中受益,例如在编辑中
  • 我会计时,但我敢打赌分支的成本比仅仅写一个不会被看到的更昂贵。如果您的源代码的大部分已知包含 alpha,您可以实现一种算法,该算法允许您跳过帧的大部分区域。
  • RLE Sprites 这是加速这种精灵引擎的老派策略
  • @gordy 感谢您的链接和答案。我查看了链接,它看起来很有趣,但是编写一种编码我的精灵的方法可能很耗时。我尝试用 memcpy 代替 DWORD 副本,它实现了不错的加速,大约 20%。
【解决方案2】:

理论上,它们应该产生相同的效果。在实践中,它可能会完全不同。

如果您打印出 OpenMP 程序的汇编代码,OpenMP 只会调用范围内的某个函数,例如 #pragma omp parallel ...。类似于folk

OpenMP 是面向并行计算的,另一方面,多线程更通用。 例如,如果您要编写 GUI 程序,则需要多线程(某些框架可能会隐藏它。它仍然需要多个线程)。但是,您永远不想使用 OpenMP 来实现它。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2023-03-10
    • 2011-12-15
    • 2013-10-16
    相关资源
    最近更新 更多