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
,这将为这些独立任务链启用管道类型的并行性。
在我的程序中,我使用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
,这将为这些独立任务链启用管道类型的并行性。