String 构造trie的并行算法?
由于trie数据结构有如此巨大的分支因子,并且每个子树都完全独立于其他子树,因此似乎应该有一种方法通过并行添加所有单词来极大地加快给定词典的trie构建 我最初的想法是:将互斥体与trie中的每个指针(包括指向根的指针)相关联,然后让每个线程遵循向trie中插入单词的正常算法。但是,在遵循任何指针之前,线程必须首先获取该指针上的锁,这样,如果它需要向trie添加新的子节点,它就可以在不引入任何数据竞争的情况下执行此操作 这种方法的缺点是它使用了大量的锁(trie中的每个指针一个锁),并执行大量的获取和释放(每个输入字符串中的每个字符一个锁)String 构造trie的并行算法?,string,algorithm,data-structures,parallel-processing,trie,String,Algorithm,Data Structures,Parallel Processing,Trie,由于trie数据结构有如此巨大的分支因子,并且每个子树都完全独立于其他子树,因此似乎应该有一种方法通过并行添加所有单词来极大地加快给定词典的trie构建 我最初的想法是:将互斥体与trie中的每个指针(包括指向根的指针)相关联,然后让每个线程遵循向trie中插入单词的正常算法。但是,在遵循任何指针之前,线程必须首先获取该指针上的锁,这样,如果它需要向trie添加新的子节点,它就可以在不引入任何数据竞争的情况下执行此操作 这种方法的缺点是它使用了大量的锁(trie中的每个指针一个锁),并执行大量的
有没有一种方法可以在不使用几乎同样多的锁的情况下并行构建一个trie?好吧,为一组节点设置锁(而不是一个节点)的细粒度和粗粒度之间存在明显的权衡 一种简单的方法是通过散列-拥有
m
不同的锁,并为每个要访问的节点获取编号为hash(node)%m
的锁。
请注意,该方法基本上是建议方法(使用完美哈希和
n==m
)和串行方法(使用m==1
)的推广
另一个可能使用的方法是——如果该方法实际上会提高性能,那么性能取决于字典的分布和trie的大小,当然,如果冲突往往非常罕见(对于非常长的单词字典来说可能是这样),则可能会有很大帮助。
其想法是在没有任何同步的情况下将单词添加到trie中,如果遇到冲突,则回滚到最后一个已知的稳定状态(当然,这需要对数据进行快照,如果我们谈论的是无法存储的数据流,则可能不可行).我刚刚想到,可以通过使用原子测试和指针上的set操作而不是锁来解除锁定。具体来说,如果线程希望跟随指针,它将执行以下操作:
希望这有帮助 一个明显的无锁算法是:
假设前缀分布均匀,这可以使您的线性加速达到字母表大小的k次方。根据字典的外观,如果可以让每个线程构建独立的子树,您可能根本不需要锁。如果这不是一个在线算法,请按前缀对单词进行预排序(如果少于26个线程,则为第一个字母;如果有更多线程,则为第一个字母;如果知道数据不平衡,则为第二个字母,例如,90%的单词以A开头)。基本上,这将是一个O(n)操作,您只需进行一次运算,计算以给定字母开头的单词数量,然后进行一次排序(按照所选前缀的基数排序)。然后,在线程之间划分前缀,并让每个线程构建这些独立的子树。最后,让一个线程将这些子树中的每一个子树添加到根。我将浏览下面的一个示例 你的字典:
树皮
苹果
饼干
和
婴儿
玉米
蓝色
蛋糕
培根 排序后:
苹果
和
树皮
婴儿
蓝色
培根
玉米
饼干
蛋糕 然后我们在线程之间划分前缀。对于本例,我们有3个线程,它们获取前缀[A][B][C],并构建以下树: A --| B -------| C -------| P N |-- A ---| L O ---| A P D R B C U O R K L K Y O E K N E E N I E A--B--C-- P N--A--L O--A P D R B C O R K 好的,好的 恩尼 E 然后有一个线程在根处组合这些线程,如: |----------- Root------------------| A --| B -------| C -------| P N |-- A ---| L O ---| A P D R B C U O R K L K Y O E K N E E N I E |-----------根------------------| A--B--C-- P N--A--L O--A P D R B C O R K 好的,好的 恩尼 E 我希望这是有道理的 此方法的优点: 线程基本上是独立工作的,您不需要处理获取和释放锁的开销 这种方法的缺点: 如果你