例如,有三个线程。
- 线程1被分配任务1、2和3
- 线程2被分配任务4、5和6
- 线程3被分配任务7、8和9
任务大小并不一致。分配给线程的任务具有非常相似的工作集,因此当这三个任务都由同一线程执行时,缓存将得到有效使用。我还应该注意到,这些任务将在具有四个节点的NUMA系统上运行。四个线程中的每一个都必须分配给系统的一个节点。
我的问题是关于负载平衡。例如,如果线程1在其他线程之前完成了任务,并且任务9没有启动,我希望Cilk调度器将任务9分配给线程1。
欢迎所有解决方案,包括Cilk Plus、OpenMP或网络上免费提供的其他调度器。
更新:必须将线程分配给NUMA系统的节点,并且必须在特定节点上分配这些线程使用的内存位置。我已经成功地将libnuma
与OpenMP一起使用。然而,我无法找到如何使用Cilk、TBB等将线程映射到节点。如果可以在Cilk Plus中获得派生工作线程的线程id,我会使用numa_run_on_node(nodeid)
将其映射到节点上。
有关Cilk在NUMA体系结构上的可伸缩性问题的更多信息:http://www.sciencedirect.com/science/article/pii/S0167739X03001845#
在Cilk中执行此操作的正确方法如下:
void task1_task2_task3()
{
cilk_spawn task1();
cilk_spawn task2();
task3();
}
void task4_task5_task6()
{
cilk_spawn task4();
cilk_spawn task5();
task6();
}
void task7_task8_task9()
{
cilk_spawn task7();
cilk_spawn task8();
task8();
}
int main()
{
cilk_spawn task1_task2_task3();
cilk_spawn task4_task5_task6();
task7_task8_task9();
cilk_sync;
finalize_stuff();
return 0;
}
请记住,cilk_spown是向调度程序建议的,cilk.spown之后的代码可能会被窃取,而不是必需的。当执行cilk_spown时,它会在worker的deque尾部推送一个符号,表示该延续可用于窃取。盗贼总是从deque的头部窃取,因此可以保证某些工人在窃取task1_task2_task3()的延续之前会窃取main()的继续。但是,由于工作程序随机选择从哪个工作程序中窃取,因此无法保证main()的最终延续会在从task1_task2_task3()中工作之前被窃取。
Barry Tannenbaum
英特尔Cilk开发