多线程分组算法

时间:2016-12-25 23:09:40

标签: vb.net multithreading algorithm grouping

我有一个圆圈集合,每个圆圈可能会也可能不会与集合中的一个或多个其他圆圈相交。我想将这些圈子分组,以便每个"组"包含所有圆圈,使得该组的每个成员与该组的至少一个其他成员相交,并且使得任何组的任何成员都不与任何其他组的任何成员相交。我已经提出了以下VB.NET /pseudocode算法来解决单个线程上的这个问题:

Dim groups As New List(Of List(Of Circle))
For Each circleToClassify In allCircles
    Dim added As Boolean
    For Each group In groups
        For Each circle In group
            If circleToClassify.Intersects(circle) Then
                group.Add(circleToClassify)
                added = True
                Exit For
            End If
        Next
        If added Then
            Exit For
        End If
    Next
    If Not added Then
        Dim newGroup As New List(Of Circle)
        newGroup.Add(circleToClassify)
        groups.Add(newGroup)
    End If
Next
Return groups

或者用英语

  1. 从圈子集合中取出每件物品
  2. 检查它是否与任何现有组的任何成员相交(请记住"组"可能只包含一个圆圈)
  3. 如果圆圈以上述方式相交,请将其添加到相应的组
  4. 否则,请创建一个以此圈为唯一成员的新群组
  5. 转到第1步。
  6. 我希望能够做的是使用任意数量的线程来执行此任务。然而,我并没有像我所有的解决方案那样做得很远到目前为止,由于锁定而最终会以串行方式执行。

    任何人都可以提供关于我想要实现这种多线程的想法吗?

2 个答案:

答案 0 :(得分:1)

一种方法是将图像划分为块,在不同的线程上独立运行每个块的算法(仅考虑其中心位于该块中的圆圈),然后加入组来自具有交叉圆的不同块。

另一种方法是使用图形来表示问题,其中节点表示圆,并且如果相应的圆相交,则在两个节点之间存在边。我们需要找到此图表的connected components。这忽略了问题的几何方面,但是,有一些通用的算法可能是有用的(例如你可以考虑this link的最后一张幻灯片。)

答案 1 :(得分:1)

TLDR

  • 最好的多线程解决方案避免共享或执行只读共享。 (因此不需要锁。)
  • 考虑对您的工作进行分区,以便线程不共享结果数据,然后合并每个线程的结果。
  • 请注意,当您去除检测圆群是否相交的细节时,您实际上是在处理连通分量图理论问题。网上有很多关于这个主题的有用资料。事实上,您可能会发现只需应用广度优先搜索算法来查找连接组件就会更容易,也更快。

详细

在进行多线程开发时,一等奖是以最小化锁定数量的方式实现线程。在最简单的情况下:如果他们不共享任何数据,他们根本不需要锁。但是,如果您可以保证在线程运行时不会修改共享数据 :那么在这种情况下您也不需要锁。

在您的问题中,您无需修改​​您的圆圈输入列表。您遇到的问题是您正在构建共享圈组列表。基本上,您正在共享结果空间并需要锁定以确保结果的完整性。

这种情况下的一种技术是“分区和合并”。作为一个简单的例子,考虑找到一大堆数字的最大值。天真(和理想的单线程解决方案)是:

  • 保持一个“当前最大值”;
  • 将每个元素与此值进行比较;
  • 如果它更高,
  • 更新 “当前最大值”。

多线程的问题发生在更新共享结果时。一种解决方案是:

  • 为每个p个线程分区列表;
  • 在每个分区中找到最大 ;
  • 一旦所有线程完成他们的工作,通过找到p分区最大值的最大值,可以轻而易举地获得最终结果。

对单线程解决方案的权衡涉及权衡分配工作负载的难易程度和每线程结果的合并与通常更简单的单线程方法相比。

分区并合并应用于圆群

  

作为旁注:注意你的问题本质上是一个图论问题,这样:每个圆都是一个节点;如果任何2个圆相交,则它们之间存在无向边;并且您正在尝试确定图表的连接组件   显然,这提供了一个可以研究更多想法/信息的领域。但更重要的是,通过简单的布尔评估2个圆是否相交,可以更容易地分析问题   还要注意通过首先将您的圈子预处理为合适的图表结构来改善潜在的效果。

假设您有8个圆圈(A-H),下表中的1表示2个圆相交。

 ABCDEFGH
A11000110
B11000000
C00100000
D00010101
E00001110
F10011100
G10001010
H00010001

一个分区的想法是通过仅考虑圆圈的子集及其所有直接连接来确定连接的内容。

 ABCDEFGH
A11000110   p1 [AB]
B11000000
---------
C00100000   p2 [CD]
D00010101
---------
E00001110   p3 [EF]
F10011100
---------
G10001010   p4 [GH]
H00010001

NB 即使线程正在共享数据(例如,2个线程可能同时考虑圆圈A和F之间的交集),该共享是只读的,不需要锁定。

假设[AB][CD][EF][GH]的4个分区(和4个线程)。每个分区的连接组件将按如下方式细分:

[AB]: ABFG
[CD]: C        DFH
[EF]: ADEFG
[GH]: AEG      DH

您现在有一个可能重叠的连接组件列表。合并涉及迭代列表以查找重叠。如果找到,则取2联的组合是一个新的连接组件。这将最终产生:ABFGDHE和C

需要考虑的一些优化技术:

  • 矩阵的左下角反映了右上角。因此,您应该能够避免重复处理反向连接。
  • 分区的合并本身可以进行分区和合并。
  • 事实上,在极端情况下,您可以开始为每个分区划分一个圆圈。
Connected(A) = ABFG
Connected(B) = B
    Connected(AB) = ABFG
Connected(C) = C
Connected(D) = DFH
    Connected(CD) = C,DFH
        Connected(ABCD) = ABFGDH,C
Connected(E) = EFG
Connected(F) = F
    Connected(EF) = EFG
Connected(G) = G
Connected(H) = H
    Connected(GH) = G,H
        Connected(EFGH) = EFG,H
            Connected(ABCDEFGH) = ABFGDHE,C
  

非常NB 您需要确保选择适当的数据结构和算法,否则会遇到极差的性能。例如。一个天真的交集实现可能需要O(n ^ 2)个操作来确定两个中间连接的组件是否相交并完全破坏你的目标,从而导致所有这些额外的复杂性。