【问题标题】:C++ Multithreading nested for loopsC++ 多线程嵌套 for 循环
【发布时间】:2013-03-28 19:12:56
【问题描述】:

首先,我对多线程知之甚少,我很难找到优化此代码的最佳方法,但多线程似乎是我应该走的路。

double
applyFilter(struct Filter *filter, cs1300bmp *input, cs1300bmp *output)
{
    long long cycStart, cycStop;

    cycStart = rdtscll();

    output -> width = input -> width;
    output -> height = input -> height;

    int temp1 = output -> width;
    int temp2 = output -> height;

    int width=temp1-1;
    int height=temp2 -1;
    int getDivisorVar= filter -> getDivisor();  
    int t0, t1, t2, t3, t4, t5, t6, t7, t8, t9;

    int keep0= filter -> get(0,0);
    int keep1= filter -> get(1,0);
    int keep2= filter -> get(2,0);
    int keep3= filter -> get(0,1);
    int keep4= filter -> get(1,1);
    int keep5= filter -> get(2,1);
    int keep6= filter -> get(0,2);
    int keep7= filter -> get(1,2);
    int keep8= filter -> get(2,2);


    //Declare variables before the loop
    int plane, row, col;    

    for (plane=0; plane < 3; plane++) {
        for(row=1; row < height ; row++) {
            for (col=1; col < width; col++) {

                t0 = (input -> color[plane][row - 1][col - 1]) * keep0;
                t1 = (input -> color[plane][row][col - 1]) * keep1;
                t2 = (input -> color[plane][row + 1][col - 1]) * keep2;
                t3 = (input -> color[plane][row - 1][col]) * keep3;
                t4 = (input -> color[plane][row][col]) * keep4;
                t5 = (input -> color[plane][row + 1][col]) * keep5;
                t6 = (input -> color[plane][row - 1][col + 1]) * keep6;
                t7 = (input -> color[plane][row][col + 1]) * keep7;
                t8 = (input -> color[plane][row + 1][col + 1]) * keep8;

                // NEW LINE HERE

                t9 = t0 + t1 + t2 + t3 + t4 + t5 + t6 + t7 + t8;
                t9 = t9 / getDivisorVar;

                if ( t9 < 0 ) {
                    t9 = 0;
                }

                if ( t9  > 255 ) {
                    t9 = 255;
                } 

                output -> color[plane][row][col] = t9;
            } ....

所有这些代码很可能都不是必需的,但它确实提供了一些上下文。因此,因为 3 个“for”循环中的第一个仅从 0-2 开始,所以我希望有一种方法可以让底部的两个“for”循环同时运行以获取不同的“平面”值。这甚至可能吗?如果是这样,它真的会让我的程序更快吗?

【问题讨论】:

  • 这就是我在简要了解多线程之后的想法,但我认为只要 t0-t9 都以某种方式在线程中是可能的?因为所有其他变量都独立于循环。
  • 确保线程中使用的所有内容都是线程本地的,因此您无需担心线程相互踩踏,除了输入和输出数组。对于那些,只需以编程方式确保您永远不会从两个不同的线程读取/写入相同的单元格,这样您就不需要同步。
  • 我刚刚使用 4 个平面和 2560x1600 图像进行了尝试。单线程耗时 109 毫秒,4 个线程耗时 47 毫秒。但是由于这个过程非常简单,创建和等待线程的开销实际上已经足够大了,但它仍然将计算所需的时间减少了一半以上。更复杂的循环肯定会从线程中受益更多。正如我所说,在这个例子中不需要任何同步(除了等待线程完成)。

标签: c++ multithreading loops optimization nested-loops


【解决方案1】:

我也会研究 OpenMP。这是一个很棒的库,它允许使用 pragma 以非常简单的方式进行线程化。 OpenMP 可在许多平台上编译,您只需要确保您的平台支持它!

我有一组代码,它有 8 级 for 循环,它的线程非常好。

【讨论】:

  • 一旦我终于让 OpenMP 以我想要的方式在我的代码中工作,它的运行速度要快得多!感谢您的建议。
【解决方案2】:

是的,完全有可能。在这种情况下,您应该摆脱事件而不必担心访问同步(即竞争条件),因为两个线程将在不同的数据集上进行操作。

这肯定会加速您在多核机器上的代码。

您可能想查看std::thread(如果您对 c++ 11 没问题)了解跨平台线程实现(因为您尚未指定目标平台)。或者threading support library更好

您还可以考虑检测内核数量并启动适当数量的线程,如 threadcount = min(planes, cores) 并为每个工作函数提供对单个平面数据集的访问权限。

【讨论】:

  • 抱歉没有指定。这将仅在 Ubuntu 机器上运行,并且我提前知道我必须使用多少个内核,因为这是一项家庭作业,因此我们能够专门围绕我们将要评分的那些机器设计我们的代码。
【解决方案3】:

看起来你可以把它分成线程,你可能会看到一个很好的速度提升。但是,您的编译器已经在尝试为您展开循环并通过矢量化指令获得并行性。您的收益可能没有您想象的那么大,尤其是当您的内存总线因来自不同位置的读取而饱和时。

您可能会考虑的是,如果这是一个 2d 图形操作,请尝试使用 OpenGL 或类似的,因为它会利用您系统上的硬件,并且其中内置了一些并行性。

【讨论】:

  • 这段代码唯一要做的就是对 2d 图像应用 3x3 矩阵过滤器并将更改后的图像扔回,那么 OpenGL 值得研究吗?
  • 如果你能用矩阵乘法来表达你正在做的事情,我当然会推荐它。我相信你想看看Shading Library。这可能比您现在可以投入更多的努力,但它肯定是一种强大的资源。
【解决方案4】:

线程版本的代码会比简单的实现慢。因为在线程版本中将花费大量时间进行同步。同样在线程版本中,您将有缓存性能缺陷。

也很有可能,3遍的外部for循环将被编译器展开并并行执行。

您可以尝试制作线程版本并比较性能。无论如何,这将是有用的经验。

【讨论】:

  • 我认为在这个特殊的例子中,他可以很容易地在没有同步的情况下逃脱。
  • 我不一定同意它将在 3 pass for 循环中并行执行。我最近有一组类似的代码,循环数也非常少(少于系统中可用线程的数量),它并没有简单地编译成多线程版本,我必须自己明确地这样做。跨度>
  • @W.B.他将需要同步原语,以保证所有线程都结束数据处理,并且可以使用结果。
  • @inkooboo 这是肯定的,但这几乎不会构成大量开销,imo。
  • @trumpetlicks 是的,可能这个循环不会展开,但无论如何简单的版本会更快
【解决方案5】:

对于这种情况,您可能会比使用自动将 for 循环转换为线程的编译器做得更糟。

使用这样的代码,编译器可以确定是否存在任何迭代间数据依赖关系。如果不是,那么它知道它可以安全地将 for 循环拆分到多个线程中,将标准线程同步放在最后。通常,这样的编译器能够插入代码,该代码在运行时确定线程的开销是否会被好处所抵消。

唯一的问题是,你有编译器吗?如果是这样,那么它是迄今为止获得线程好处的最简单的方法,以实现像这样的直接、几乎公开的并行性。

我知道 Sun 的 C 编译器可以做到这一点(我认为他们是最早这样做的公司之一。它可能只在他们的编译器的 Solaris 版本上)。我认为英特尔的编译器也可以。我对 GCC 有疑问(尽管我很乐意在这一点上得到纠正),而且我对 Microsoft 的编译器不太确定。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2015-10-15
    • 2022-01-21
    • 2021-03-20
    • 2017-07-29
    • 2022-01-26
    • 2016-04-22
    • 1970-01-01
    相关资源
    最近更新 更多