boots::spirit::qi 解析的 TBB 并行化

TBB parallelization of parsing with boots::spirit::qi

在我的程序中,我使用Boost-Spirit-Qi 来解析大数据集。输入数据是顺序记录。我正在尝试使用 TBB 来提高解析效率。并行处理的过程如下:

typedef map<string, data_struct_t> mdata_t;
vector<string> text; 
mdata_t  data;

parallel_for(blocked_range<size_t>(0, input.size(), gs),
                     [&]  (blocked_range<size_t>& r) {
        data_struct_t cs;
        mdata_t cr;
        string s;
        for(size_t i=r.begin(); i<r.end(); i++) {
           s = text[i];         
           Parser::task1(s, cs); 
           Parser::task2(s, cs); 
           Parser::task3(s, cs);
        ....
           Parser::task8(s, cs);   
           cr.insert(std::make_pair(cs.title, cs));
        }
        data.insert(cr.begin(), cr.end());  

 }, ap);

我的程序只使用了 CPU 的 10%(2 CPU,16 个核心)并且在 8 个核心上工作。我不明白为什么不使用剩余的 8 个内核(单处理器)。 如果能指出正确的算法并行化此任务,我将不胜感激。

感谢您的建议。

斯坦

您的 input.size() 可能太小或 gs 太大而无法创建足够的并行度。否则,如果线程数是一个问题,请在启动时检查程序的进程(关联)掩码以及 TBB 是如何初始化的(例如,如果 tbb::task_scheduler_init 是用少量线程创建的)。

至于 CPU 利用率,当您​​的工作受 IO 限制时(即读取文件),这是预期的。完成一次并行迭代所需的时间也可能与另一次迭代相差很多。在这种情况下,甚至在创建所有线程之前就可能完成小的迭代。 (如果你想准确测量加速比,你应该在所有线程都运行时手动等待)

建议:

你有一个关于 data.insert 的错误,因为 std::map 对于并发修改是不安全的。使用 tbb::concurrent_unordered_map 或仅 tbb::parallel_reduce 以合并在 cr 中从不同线程收集的部分结果。

如果任务不共享全局状态,模式 Parser::task1(s, cs); ... Parser::task8(s, cs); 也可以并行化。请参阅 tbb::parallel_pipeline,这将为这些独立任务链启用管道类型的并行性。