我需要一种遍历二叉树的方法,使用多个线程并将符合条件的元素存储到列表中。 我如何以线程安全的方式做到这一点?
答案 0 :(得分:6)
正如SDG指出的那样,答案很大程度上取决于问题的确切性质。如果你想分解遍历(即并行遍历),那么你可以让线程在第2级之后作用于不同的子树。然后每个线程可以附加到它自己的列表,然后可以在连接点处合并/连接。最简单的方法是在进行遍历时阻止对树的mod。
我只需要补充一点,在达到关卡后你不会继续开火。你只做一次。所以在2级你最多可以发射4个线程。每个traveral线程都将它的子树视为自己的root树。除非你有一些节点和一个合理平衡的树,否则你也不会这样做。 Buttload是一个技术术语,意思是“衡量”。 UI线程遍历遍历分裂点的遍历部分。如果这是我的问题,我会长时间地思考我需要实现的目标,因为它可能会产生重大影响。
让我再添加一件事(这会成为Monty Python草图吗?)。如果您只需要处理结果,则不需要将结果列表连接或合并到新列表中。即使您需要排序的结果,最好还是单独对每个列表进行排序(可能并行),然后以GetNextItem拉式方式“合并”它们。这样你就不需要额外的内存了。您可以通过两个“缓冲区”(可以是实际条目的指针/索引)以这种方式一次合并4个列表。我试图找到一种方法来解释它,而不用绘制图片。
0 1 2 3 4 5 6 7 8 9
L1(0): 4 4 4 5 5 6 8
B1[L2,3] \
L2[1]: 3 4 5 5 6 7 7 8 9
\
L3[1]: 2 2 4 4 5 5 6 8
B2[L3,2] /
L4[0]: 2 4 5 5 6 7 7 8 9
您不断从满足所需订单的列表中提取。如果你从B2拉,那么你只需要更新B2及其子列表(在这种情况下,我们从L3中拉出2并将L3的索引移动到下一个条目。)
答案 1 :(得分:1)
你会错过一些有助于回答的观点。
如果多个线程在遍历中都是只读的,并且树在遍历期间没有改变,并且它们都将这些找到的匹配放入那些遍历线程拥有的列表中,那么你应该没有一点都不担心。
当你放松任何这些限制时,你需要添加锁定或其他适当的方法来确保它们很好地协同工作。
答案 2 :(得分:1)
最简单的方法是锁定二叉树类的入口点,并假设它被锁定在递归遍历函数上(用于插入,查找,删除)。
如果您有许多读者和更少的作者,您可以使用ReaderLocks
和WriterLocks
来允许并发查找,但完全锁定突变。
如果你想要更细粒度的东西,它将变得更加复杂。您必须从“线程安全”中定义您真正需要的内容,您可能必须削减二叉树API,并且您可能需要单独锁定节点,可能是在子树遍历期间。 / p>