英特尔 tbb 任务调度是否适合 DBMS?
Is Intel tbb task scheduling suitable for a DBMS?
所以我遇到了 Intel TBB 并问自己它是否适合某种 DBMS?
例如,我有一个名为进程查询的任务,它在我的系统中执行一条语句,并通过 return 参数 return 执行某些操作。
这看起来像这样的例子:
class ProcessQuery : public task {
private:
int a;
public:
ProcessQuery(int n, char* result) :a(n){};
task* execute() {
//do something and write the result
}
};
要执行这个,我会这样做(这只是一个例子!):
tbb::task_scheduler_init init(tbb::task_scheduler_init::automatic);
//init of the parameter for the tasks
ProcessQuery &q1 = *new(tbb::task::allocate_root()) ProcessQuery(1, r1);
ProcessQuery &q2 = *new(tbb::task::allocate_root()) ProcessQuery(2, r2);
ProcessQuery &q3 = *new(tbb::task::allocate_root()) ProcessQuery(3, r3);
tbb::task::spawn(q1);
tbb::task::spawn(q2);
tbb::task::spawn(q3);
此外,我需要一些循环并检查是否有结果并将其发送回查询客户端的任务。所以会有一个任务是根任务,并且将那些 ProcessQuery
任务作为子任务。或者甚至任务让客户端作为参考传递并在他完成后发送结果。
那么这是否合适,或者是否有更好的解决方案或多或少开箱即用且功能强大? (也许我对 tbb 的 taskscheduler 有误,我知道的 lib 里面还有更多)
让我先修正一下你的古老风格的例子。由于 tbb::task
是低级别的 API 而 task_scheduler_init
是可选的,所以我不建议从它们开始。使用高级 API 代替,例如task_group
:
tbb::task_group tg;
int a;
tg.run([=a]{ /*do something and write the result*/ }); a++;
tg.run([=a]{ /*do something and write the result*/ }); a++;
tg.run([=a]{ /*do something and write the result*/ }); a++;
// ...
tg.wait(); // recommended before program termination
关于你的问题,TBB主要是为并行计算而设计的,它对文件I/O和网络等阻塞操作没有足够的支持。因为这些操作会阻塞 OS 中的工作线程并导致 CPU 资源利用不足,因为 TBB 限制了工作线程的数量以防止 oversubscription.
但是当阻塞操作仅限于一个线程并且 TBB 工作进程处理它产生的事件时,TBB 适合异步 I/O。当还没有传入事件时,主线程的过度使用存在一个小问题,但它可以解决,甚至可以在 TBB 调度程序中修复。
这种生产者-消费者模式的一种简单的高级方法是使用 parallel_pipeline:
void AsyncIO() {
parallel_pipeline( /*max_number_of_live_token=*/
4*task_scheduler_init::default_num_threads(),
make_filter<void, event_t>(
filter::serial, // only one thread can get events
[](flow_control& fc)-> event_t {
event_t e;
if( !get_event(e) ) {
fc.stop(); // finish pipeline
return event_t(); // empty event
}
return e;
}
) &
make_filter<event_t, void>(
filter::parallel, // events can be processed in parallel
[&](event e) {
process_event(e);
enqueue_response(e); // do not block when write/send back
}
)
);
}
总而言之,如果您可以将您的操作拆分为阻塞和非阻塞,并将所有阻塞操作分离到专用线程,TBB 可以帮助组织可扩展的计算并通过在每个请求中处理它来减少延迟并行.
所以我遇到了 Intel TBB 并问自己它是否适合某种 DBMS?
例如,我有一个名为进程查询的任务,它在我的系统中执行一条语句,并通过 return 参数 return 执行某些操作。 这看起来像这样的例子:
class ProcessQuery : public task {
private:
int a;
public:
ProcessQuery(int n, char* result) :a(n){};
task* execute() {
//do something and write the result
}
};
要执行这个,我会这样做(这只是一个例子!):
tbb::task_scheduler_init init(tbb::task_scheduler_init::automatic);
//init of the parameter for the tasks
ProcessQuery &q1 = *new(tbb::task::allocate_root()) ProcessQuery(1, r1);
ProcessQuery &q2 = *new(tbb::task::allocate_root()) ProcessQuery(2, r2);
ProcessQuery &q3 = *new(tbb::task::allocate_root()) ProcessQuery(3, r3);
tbb::task::spawn(q1);
tbb::task::spawn(q2);
tbb::task::spawn(q3);
此外,我需要一些循环并检查是否有结果并将其发送回查询客户端的任务。所以会有一个任务是根任务,并且将那些 ProcessQuery
任务作为子任务。或者甚至任务让客户端作为参考传递并在他完成后发送结果。
那么这是否合适,或者是否有更好的解决方案或多或少开箱即用且功能强大? (也许我对 tbb 的 taskscheduler 有误,我知道的 lib 里面还有更多)
让我先修正一下你的古老风格的例子。由于 tbb::task
是低级别的 API 而 task_scheduler_init
是可选的,所以我不建议从它们开始。使用高级 API 代替,例如task_group
:
tbb::task_group tg;
int a;
tg.run([=a]{ /*do something and write the result*/ }); a++;
tg.run([=a]{ /*do something and write the result*/ }); a++;
tg.run([=a]{ /*do something and write the result*/ }); a++;
// ...
tg.wait(); // recommended before program termination
关于你的问题,TBB主要是为并行计算而设计的,它对文件I/O和网络等阻塞操作没有足够的支持。因为这些操作会阻塞 OS 中的工作线程并导致 CPU 资源利用不足,因为 TBB 限制了工作线程的数量以防止 oversubscription.
但是当阻塞操作仅限于一个线程并且 TBB 工作进程处理它产生的事件时,TBB 适合异步 I/O。当还没有传入事件时,主线程的过度使用存在一个小问题,但它可以解决,甚至可以在 TBB 调度程序中修复。
这种生产者-消费者模式的一种简单的高级方法是使用 parallel_pipeline:
void AsyncIO() {
parallel_pipeline( /*max_number_of_live_token=*/
4*task_scheduler_init::default_num_threads(),
make_filter<void, event_t>(
filter::serial, // only one thread can get events
[](flow_control& fc)-> event_t {
event_t e;
if( !get_event(e) ) {
fc.stop(); // finish pipeline
return event_t(); // empty event
}
return e;
}
) &
make_filter<event_t, void>(
filter::parallel, // events can be processed in parallel
[&](event e) {
process_event(e);
enqueue_response(e); // do not block when write/send back
}
)
);
}
总而言之,如果您可以将您的操作拆分为阻塞和非阻塞,并将所有阻塞操作分离到专用线程,TBB 可以帮助组织可扩展的计算并通过在每个请求中处理它来减少延迟并行.