如何使用 tbb::parallel_for 和 tbb::dataflow 并行化我的处理?
How to go about parallelizing my processing using tbb::parallel_for and tbb::dataflow?
我有一个文件源需要处理。
从每个文件,我的代码生成可变数量的数据对象,我们称之为 N。
我有K个处理对象可以用来处理N个数据对象。
我正在考虑使用 Tbb:dataflow 执行以下操作:
- 创建一个function_node并发K个,把我的K个处理对象放到一个concurrent_queue.
- 使用input_node读取文件,生成N个数据对象,并try_put分别放入function_node.
- function_node 主体使处理对象出队,用它来处理数据对象,然后 returns 处理对象在完成后返回 concurrent_queue。
我能想到的另一种方式可能是这样的:
- 创建具有串行并发的 function_node。
- 使用input_node读取文件,生成N个数据对象,将数据对象放入集合中发送给function_node。
- 在 function_node 处,将 N 个对象划分为 K 个范围,并使用 K 个处理对象中的每一个同时处理每个范围 - 不确定是否可以为此目的自定义 parallel_for .
第一种方法的优点可能是延迟较低,因为我可以在生成数据对象的那一刻就开始通过数据流发送数据对象,而不必等待生成所有 N 个数据对象。
您认为并行化此处理的最佳方式是什么?
是的,您是对的,第一种方法具有无需等待所有数据对象开始处理的优点。但是,它还有一个优点,即无需等待处理完所有传递给 parallel_for
的数据对象。如果每个处理对象的每个数据对象的处理速度不同 and/or,这一点就变得尤为明显。
此外,buffer_node
后跟(也许 reserving
)join_node
而不是 concurrent_queue
似乎足以保存处理对象以供进一步重用。在这种情况下,一旦完成数据对象的处理,function_node
会将 return 处理对象返回给 buffer_node
。因此,图表将如下所示:
input_node -> input_port<0>(join_node);
buffer_node -> input_port<1>(join_node);
join_node -> function_node;
function_node -> buffer_node;
在这种情况下,function_node
的并发数可以保留为 unlimited
,因为它会自动跟随图中存在的处理对象数 (available tokens) .
另外请注意,从不同文件生成数据对象也可以并行完成。如果您看到这样做的好处,请考虑使用 function_node
而不是 input_node
,因为后者始终是连续的。但是,在这种情况下,使用 join_node
和 queueing
策略,因为 function_node
不可预留。
此外,请考虑使用 tbb::parallel_pipeline instead as it seems you have a classic pipelining scheme of processing. In particular, this and that link 可能会有用。
我有一个文件源需要处理。 从每个文件,我的代码生成可变数量的数据对象,我们称之为 N。 我有K个处理对象可以用来处理N个数据对象。
我正在考虑使用 Tbb:dataflow 执行以下操作:
- 创建一个function_node并发K个,把我的K个处理对象放到一个concurrent_queue.
- 使用input_node读取文件,生成N个数据对象,并try_put分别放入function_node.
- function_node 主体使处理对象出队,用它来处理数据对象,然后 returns 处理对象在完成后返回 concurrent_queue。
我能想到的另一种方式可能是这样的:
- 创建具有串行并发的 function_node。
- 使用input_node读取文件,生成N个数据对象,将数据对象放入集合中发送给function_node。
- 在 function_node 处,将 N 个对象划分为 K 个范围,并使用 K 个处理对象中的每一个同时处理每个范围 - 不确定是否可以为此目的自定义 parallel_for .
第一种方法的优点可能是延迟较低,因为我可以在生成数据对象的那一刻就开始通过数据流发送数据对象,而不必等待生成所有 N 个数据对象。
您认为并行化此处理的最佳方式是什么?
是的,您是对的,第一种方法具有无需等待所有数据对象开始处理的优点。但是,它还有一个优点,即无需等待处理完所有传递给 parallel_for
的数据对象。如果每个处理对象的每个数据对象的处理速度不同 and/or,这一点就变得尤为明显。
此外,buffer_node
后跟(也许 reserving
)join_node
而不是 concurrent_queue
似乎足以保存处理对象以供进一步重用。在这种情况下,一旦完成数据对象的处理,function_node
会将 return 处理对象返回给 buffer_node
。因此,图表将如下所示:
input_node -> input_port<0>(join_node);
buffer_node -> input_port<1>(join_node);
join_node -> function_node;
function_node -> buffer_node;
在这种情况下,function_node
的并发数可以保留为 unlimited
,因为它会自动跟随图中存在的处理对象数 (available tokens) .
另外请注意,从不同文件生成数据对象也可以并行完成。如果您看到这样做的好处,请考虑使用 function_node
而不是 input_node
,因为后者始终是连续的。但是,在这种情况下,使用 join_node
和 queueing
策略,因为 function_node
不可预留。
此外,请考虑使用 tbb::parallel_pipeline instead as it seems you have a classic pipelining scheme of processing. In particular, this and that link 可能会有用。