linux 第一次并行运行for_each的速度慢了10倍

xpcnnkqh  于 12个月前  发布在  Linux
关注(0)|答案(1)|浏览(149)

我有一些专有代码,基本上执行一个三重for循环。我决定通过将其中一个循环移动到std::execution::par_unseq策略的std::for_each结构中来加速。
这段代码更新了一些共享的std::vector,它现在被一个互斥锁保护着。这段代码没有静态局部变量。

std::vector<OutputType>
Detector::Detect(
    const std::vector<Points>& path,
    const std::vector<Object>& objects) const {
    std::vector<OutputType> hits;
    std::mutex mtx;

        std::for_each (std::execution::par_unseq,
        objects.cbegin(),
        objects.cend(),
        [&](auto const& obj){
            std::set<ObjectId> already_hit;

            for (size_t i = 0; i < path.size(); ++i) {
                if (already_hit.contains(obj.id_)) {
                    continue;
                }
                for (size_t j = 0; j < obj.convex_hull.size(); ++j) {
                    auto pt = CalcThings(path[i], obj.convex_hull[j]),;
                    if (Condition(pt, path[i])) {
                        {
                            std::lock_guard<std::mutex> lock(mtx);
                            hits.emplace_back(OutputType(path[i], obj.id_));
                        }
                        already_hit.insert(obj.id_);
                        break;
                    }
                }
            }
        });

    return hits;
}

字符串
我有一个驱动程序代码,在检查下运行代码并测量执行时间。为了消除疑虑,tic和toc将一些静态初始化带入故事,我在for之前调用了这对代码。

for (int i = 0; i < 100; ++i) {
        FrameContent content = ReadNextFrame();

        if (content.valid) {
            Detector detector(args);

            {
                tic(0, "detector_name", content.path.size(),
                    content.objects.size());

                detector.Detect(content.path, content.objects);

                toc();
            }
        }
    }


然而,保存到文件中的输出看起来很奇怪,因为第一次运行需要相当多的时间:
| 检测器|NS|患者数量|# objs|
| --|--|--|--|
| 让静力学浪费时间| 190 | 0 | 0 |
| 检测器名称| 4400605 | 655 | 41 |
| 检测器名称| 538334 | 609 | 41 |
| 检测器名称| 494972 | 645 | 41 |
| 检测器名称| 435749 | 643 | 44 |
| 检测器名称| 408687 | 608 | 44 |
| 检测器名称| 398247 | 637 | 41 |
| 检测器名称| 387577 | 644 | 43 |
| 检测器名称| 382989 | 626 | 45 |
| 检测器名称| 396695 | 655 | 44 |
| 检测器名称| 368802 | 604 | 41 |
| 检测器名称| 379612 | 606 | 41 |
| 检测器名称| 377248 | 602 | 43 |
| 检测器名称| 382789 | 604 | 43 |
| 检测器名称| 418576 | 679 | 43 |
| 检测器名称| 392887 | 609 | 47 |
| 检测器名称| 490854 | 608 | 49 |
| 检测器名称| 413126 | 605 | 48 |
| 检测器名称| 456449 | 678 | 51 |
| 检测器名称| 466518 | 664 | 46 |
| 检测器名称| 428225 | 643 | 43 |
| 检测器名称| 378280 | 607 | 46 |
| 检测器名称| 392197 | 624 | 50 |
| 检测器名称| 401313 | 641 | 43 |
| 检测器名称| 448904 | 681 | 45 |
| 检测器名称| 421893 | 643 | 45 |
| 检测器名称| 446910 | 682 | 42 |
| 检测器名称| 491936 | 678 | 46 |
让我很困扰的是第一帧的运行时间要高出一个数量级,这与其中的数据量无关。
为什么会发生这种情况?是不是虚拟表的缓存(Detector是一个实现了override接口的类)?

gj3fmq9x

gj3fmq9x1#

感谢@HolyBlackCat,问题似乎是ThreadPool初始化。
我添加了一个简单的:

void TryInitializeTheThreadPool(){
    std::vector<int> nums(10000);
    for(auto i = 0; i < nums.size(); ++i) {
        nums[i] = i;
    }

    std::for_each(std::execution::par_unseq, nums.begin(), nums.end(),
        [](auto& n){ n *= 2; });
}

字符串
结果如下(注意,下面的条目是针对向量中的100'000和1' 000 '000个元素)
| 检测器|NS|患者数量|# objs|
| --|--|--|--|
| detector_name(vec size 10'000)| 1361699 | 655 | 41 |
| detector_name(vec大小100'000)| 776356 | 655 | 41 |
| detector_name(vec size 1'000'000)| 699039 | 655 | 41 |
我想,第一次尝试确实创建了一些线程,但需要更多,因此可以实现额外的时间削减。

相关问题