我一直在修补BSP树一段时间,我也玩线程.当向BSP树添加三角形时,出现了为并行处理数据而创建新线程的机会.
insert(triangle, bspnode) { .... else if(triangle spans bspnode) { (frontpiece, backpiece) = plane_split(triangle, bspnode) insert(frontpiece, bspnode.front) insert(backpiece, bspnode.back) } .... }
上面的两个插入操作可以由两个线程执行,并且由于它们不修改相同的数据,因此可以使用廉价的同步.
insert(triangle, bspnode) { .... else if(triangle spans bspnode) { (frontpiece, backpiece) = split(triangle, bspnode) handle = beginthread(insert(backpiece, bspnode.front)) insert(frontpiece, bspnode.back) if(handle) { waitforthread(handle) } else { insert(backpiece, bspnode.front) } } .... }
这个新方法尝试创建一个并行完成操作的线程,但是如果无法创建线程则不应该失败(它将简单地恢复为原始算法).
这是一个合理的编程习惯,还是我不正确地使用线程?我还没有找到关于这种技术的任何文献.我喜欢它倾向于使用我的CPU(2核),理论上可以扩展到任何数量的可用处理器.我不喜欢它在CPU和内存上可能会非常浪费.
如果处理的某些部分正在等待外部事件(用户输入,I/O,一些其他处理),则线程很好 - 正在等待的线程可以继续等待,而一个线程没有等待前进.
但是,对于处理密集型任务,比处理器更多的线程实际上会产生开销.看起来你的线程正在做所有"CPU工作",所以我坚持每个核心一个线程 - 测试找到最佳数字.
创建的最大开销来自上下文切换(冻结一个线程并加载下一个线程的执行上下文),以及线程执行具有不同内存的任务时的缓存未命中(如果您的线程可以有效地使用CPU缓存).