【问题标题】:Multithreaded Image Processing slower than Single Thread?多线程图像处理比单线程慢?
【发布时间】:2023-03-31 21:30:02
【问题描述】:

我正在使用 Objective-C 处理图像并尝试了 Grand Central Dispatch,结果很糟糕。 CPU 使用率增加了一倍,处理图像的时间也增加了一倍。

- (void) processImage:(struct ImageData)image {
    imageData = image;

    [allyMinionManager prepareForPixelProcessing];

    int cores = 4;
    int section = imageData.imageHeight/cores;
    if (section < 1) {
        section = 1;
    }
    dispatch_group_t group = dispatch_group_create();

    for (int i = 0; i < cores; i++) {
        int yStart = section * i;
        int yEnd = yStart + section;
        if (i == cores - 1) {
            yEnd = imageData.imageHeight;
        }
        dispatch_group_enter(group);
        dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_HIGH, 0), ^{
            for (int y = yStart; y < yEnd; y++) {
                uint8_t *pixel = imageData.imageData + (y * imageData.imageWidth)*4;
                for (int x = 0; x < imageData.imageWidth; x++) {
                    [allyMinionManager processPixel:pixel x:x y:y];

                    pixel += 4;
                }

            }
            dispatch_group_leave(group);
        });
    }
    dispatch_group_wait(group, DISPATCH_TIME_FOREVER);
    [allyMinionManager postPixelProcessing:imageData];
}

我在核心之间分离图像,然后等待分派的任务完成。如果我有一个 1200x800 的图像,每个线程应该处理 240,000 像素。

Core 设置为 1:95% CPU 使用率,16ms 处理时间

Core 设置为 4:120% CPU 使用率,33ms 处理时间

知道为什么性能这么差吗?

(额外问题:当我将编译器优化标志设置为最低时,我的程序中的 CPU 使用率从 45% 变为 300%。这正常吗?)

【问题讨论】:

  • 我切换到 dispatch_apply,似乎比我以前的方法好很多。虽然我的 CPU 使用率在 2 个内核时上升了 10%,但在 4 个或更多内核时上升了 50%。我没有测试处理速度,因为它发生得太快了,我的处理以恒定的 60fps 运行。我会让它保持多线程,以防我的处理变得过于密集并且 1 个核心运行速度低于 60fps。如果您将其粘贴为答案,我会将您的评论标记为答案。

标签: objective-c multithreading image-processing grand-central-dispatch


【解决方案1】:

我经常发现使用多线程代码通常无法获得理论上预期的好处。收益递减。请参阅iOS Concurrency - Not reaching anywhere's near theoretical maximum 进行更全面的讨论。

注意,您可以使用dispatch_group_async,这样就无需手动进入和离开组(仅当您分派的代码块本身是异步的时,您才需要这样做)。更好的是,鉴于您在最后等待,您应该考虑使用dispatch_apply,这样可以完全消除该组。

使用dispatch_apply,在 Mac 上运行我发现 2 个线程占用了单线程实现的 78% 的运行时间,4 个占用了 47% 的时间,8 个占用了 38% 的时间。因此,线程数量的增加带来了好处,但收益递减。

在 iPhone 6+ 上,当我从 1 个线程增加到 2 个线程时,我体验到了类似的性能提升,但是当我增加到 4 个或 8 个线程时,我发现没有进一步的性能提升。

所以,最重要的是,我建议尝试dispatch_apply。如果设备上的性能改进很快就趋于平稳,请不要感到惊讶。所以尝试只使用 2 个“核心”,看看结果如何。

【讨论】:

    猜你喜欢
    • 2016-11-08
    • 2012-09-05
    • 1970-01-01
    • 1970-01-01
    • 2018-06-03
    • 2020-08-15
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多