使用OpenMP并行化输出

Fre*_*Foo 2 c c++ parallel-processing openmp

我编写了一个必须处理大量数据的C++应用程序.使用OpenMP我很好地并行化了处理阶段,并且令人尴尬地发现输出写入现在是瓶颈.我决定也使用parallel for那里,因为我输出项目的顺序是无关紧要的; 它们只需要输出为连贯的块.

下面是输出代码的简化版本,显示除"两个自定义迭代器"中的两个自定义迭代器之外的所有变量.我的问题是:这是解决这个问题的正确和最佳方法吗?我读到了关于barrierpragma的内容,我需要它吗?

long i, n = nrows();

#pragma omp parallel for
for (i=0; i<n; i++) {
    std::vector<MyData> related;
    for (size_t j=0; j < data[i].size(); j++)
        related.push_back(data[i][j]);
    sort(related.rbegin(), related.rend());

    #pragma omp critical
    {
        std::cout << data[i].label << "\n";
        for (size_t j=0; j<related.size(); j++)
            std::cout << "    " << related[j].label << "\n";
    }
}
Run Code Online (Sandbox Code Playgroud)

(我标记了这个问题,c因为我认为OpenMP在C和C++中非常相似.如果我错了,请纠正我.)

Kon*_*lph 8

解决输出争用的一种方法是将线程本地输出写入字符串流(可以并行完成),然后将内容推送到cout(需要同步).

像这样的东西:

#pragma omp parallel for
for (i=0; i<n; i++) {
    std::vector<MyData> related;
    for (size_t j=0; j < data[i].size(); j++)
        related.push_back(data[i][j]);
    sort(related.rbegin(), related.rend());

    std::stringstream buf;
    buf << data[i].label << "\n";
    for (size_t j=0; j<related.size(); j++)
        buf << "    " << related[j].label << "\n";

    #pragma omp critical
    std::cout << buf.rdbuf();
}
Run Code Online (Sandbox Code Playgroud)

这提供了更细粒度的锁定,并且性能应该相应地增加.另一方面,这仍然使用锁定.另一种方法是使用流缓冲区数组,每个线程一个,并在并行循环cout按顺序推送它们.这具有避免昂贵锁定的优点,并且输出必须被串行化.cout

另一方面,您甚至可以尝试省略critical上面代码中的部分.根据我的经验,这是有效的,因为底层流有自己的控制并发的方式.但我相信这种行为是严格的实现定义而不是可移植的.