首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >线程似乎放慢了图像处理的速度,C++11

线程似乎放慢了图像处理的速度,C++11
EN

Stack Overflow用户
提问于 2015-04-15 19:17:45
回答 3查看 129关注 0票数 0

我正在编写一个函数来改变图像中像素的值。它的工作方式是将每个像素的阴影分割成多个线程。例如,如果有4个线程,那么每个线程将每4个像素显示一次。我发现奇怪的是,线程方法比在单个循环中的执行速度慢1/10秒。我不明白为什么会这样,因为我有一个四核CPU,并且线程之间没有真正的同步。我希望它的速度大约快4倍,减去一些开销。我在这里做错什么了吗?

请注意,我将nthreads=1设置为度量单循环方法。

FYI光栅是类中的指针,指向像素的动态数组。

代码语言:javascript
复制
void RGBImage::shade(Shader sh, size_t sx, size_t sy, size_t ex, size_t ey)
{
    validate();
    if(ex == 0)
        ex = width;
    if(ey == 0)
        ey = height;

    if(sx < 0 || sx >= width || sx >= ex || ex > width || sy < 0 || sy >= height || sy >= ey
            || ey > height)
        throw std::invalid_argument("Bounds Invalid");

    size_t w = ex - sx;
    size_t h = ey - sy;
    size_t nthreads = std::thread::hardware_concurrency();
    if(nthreads > MAX_THREADS)
        nthreads = MAX_THREADS;
    else if(nthreads < 1)
        nthreads = 1;

    size_t load_per_thread = w * h / nthreads;
    if(load_per_thread < MIN_THREAD_LOAD)
        nthreads = (w * h) / MIN_THREAD_LOAD;

    clock_t start = clock();
    if(nthreads > 1)
    {
        std::unique_ptr<std::thread[]> threads(new std::thread[nthreads]);
        for(size_t i = 0; i < nthreads; i++)
            threads[i] = std::thread([=]()
            {   
                for(size_t p = i; p < (w * h); p += nthreads)
                {   
                    size_t x = sx + p % w;
                    size_t y = sy + p / w;
                    sh(raster[y * width + x], x, y);
                }
            });
        for(size_t i = 0; i < nthreads; i++)
            threads[i].join();
    }
    else
    {
        for(size_t p = 0; p < (w * h); ++p)
        {
            size_t x = sx + p % w;
            size_t y = sy + p / w;
            sh(raster[y * width + x], x, y);
        }
    }
    std::cout << ((float)(clock() - start) / CLOCKS_PER_SEC) << std::endl;
}

我听取了一些建议,改变了我的职能。

代码语言:javascript
复制
void RGBImage::shade(Shader sh, bool threads)
{
    validate();
    clock_t c = clock();
    if(threads)
    {
        int nthreads = std::thread::hardware_concurrency();
        size_t pix = width * height;
        if(nthreads < 1)
            nthreads = 1;
        else if(nthreads > MAX_THREADS)
            nthreads = MAX_THREADS;
        if(pix / nthreads < MIN_THREAD_LOAD)
            nthreads = pix / MIN_THREAD_LOAD;

        size_t pix_per_threads = pix / nthreads;

        std::unique_ptr<std::thread[]> t(new std::thread[nthreads]);
        for(int i = 0; i < nthreads; i++)
        {
            t[i] = std::thread([=]()
            {
                size_t offset = i * pix_per_threads;
                size_t x = offset % width;
                size_t y = offset / width;
                sh(raster + offset, *this, x, y, 
                        i == nthreads - 1 ? pix_per_threads + (width * height) % nthreads : pix_per_threads);
            });
        }
        for(int i = 0; i < nthreads; i++)
            t[i].join();
    }
    else
    {
        sh(raster, *this, 0, 0, width * height);
    }
    std::cout << ((float)(clock() - c) / CLOCKS_PER_SEC) << std::endl;
}

现在,它的运行速度大约快了10倍,但线程版本的运行速度仍然较慢。

EN

回答 3

Stack Overflow用户

回答已采纳

发布于 2015-04-15 19:26:03

您所做的是最大化线程之间的争用。

你想把它降到最低。

线程应该一次(或更多)在scanline上工作。将您的图像划分为n个大致相同数目的扫描线块(从图像左侧到右侧),并告诉每个线程在第n个扫描线块上工作。

代码语言:javascript
复制
std::vector<std::thread> threads;
threads.reserve(nthreads);
for(size_t i = 0; i < nthreads; i++) {
  size_t v_start = (h*i)/nthreads;
  size_t v_end = (h*(i+1))/nthreads;
  threads.push_back(std::thread([=]()
  {   
    for(size_t y = v_start; y < v_end; ++y)
    {   
      for (size_t x = 0; x < w; ++x) {
        sh(raster[y * width + x], x, y);
      }
    }
  }));
}
for(auto&& thread:threads)
  thread.join();

另一种方法是获取ppl (并行模式库)并使用它。它将根据当前负载和硬件规范动态平衡线程数,并可能使用线程池来降低线程启动成本。

一个严重的问题是您的Shader sh。您不希望在每像素的基础上调用像函数指针(或者更昂贵的,std::function)那样昂贵的东西。

我的一般规则是编写一个“每个像素”函数,该函数将像素操作作为一个F&&,并将其传递给“为每个扫描线”函数,然后将像素着色器包装在一个(在头文件中)扫描行操作中。然后将间接的成本降低到每条扫描线一次。此外,编译器可以优化像素之间的操作(例如,执行SIMD),而每个像素的调用不能这样优化。

与您的“交织”解决方案的最后一个问题是,它使编译器无法向量化您的代码。矢量化可以很容易地提供3-4倍的加速比。

票数 6
EN

Stack Overflow用户

发布于 2015-04-16 03:29:50

这个答案很简单。线程解决方案实际上更快。它只是消耗了更多的时钟()时间,而clock()函数对计时线程没有好处。

票数 0
EN

Stack Overflow用户

发布于 2015-04-15 19:25:35

在C++中,您可以利用这些内核的并行性,也可以使用amp (加速大规模并行)。我将投票支持后者。

示例放大器项目:http://austin.codeplex.com/

https://msdn.microsoft.com/en-us/library/hh265137.aspx http://blogs.msdn.com/b/nativeconcurrency/archive/2012/08/30/learn-c-amp.aspx

票数 -2
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/29658908

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档