生成排列可以并行进行吗?

时间:2018-11-11 15:03:04

标签: python parallel-processing permutation combinatorics

我正在尝试找出是否可以加快排列的产生。具体来说,我要在[a-zA]中使用8,在[a-zA-Z]中使用8,在[a-zA-Z0-9]中使用8。我知道很快就会花费大量的时间和空间。

即使从小写ASCII字符开始的长度为8的置换也需要花费一些时间并生成千兆字节。我的问题是我不了解底层算法,因此无法确定是否可以将问题分解为比以后可以加入的更小的任务。

我用来生成排列列表的python脚本:

import string
import itertools
from itertools import permutations

comb = itertools.permutations(string.ascii_lowercase, 8)

f = open('8letters.txt', 'w')
for x in comb:
        y = ''.join(x)
        f.write(y + '\n')

f.close()

有人知道如何将其划分为子任务,然后再将它们放在一起吗?可能吗?

我可能只是尝试一种(可能)更快的方法,但是我在使用C ++及其std :: next_permutation()时遇到了麻烦,因此我无法验证它是否可以加快速度?

如果我可以将其划分为16个任务,并在16个Xeon CPU上运行,然后加入结果,那就太好了。

1 个答案:

答案 0 :(得分:7)

如果只是置换的 ,这将非常容易:只需并行化字符串的第一个字母,然后让每个线程添加字符串的尾部即可。这将给您26个独立的任务。如果那还不够,您可以并行处理前两个字母。

您希望有一个置换而不是替换,因此问题不会轻易分解。如果只想从一组26、52和62中选择8个字母,则可以做一个幼稚的事情:对第一个字母进行并行处理,让线程只创建带有替换的尾部,并丢弃包含重复项的生成字符串。但是,当您要从26个字母中选择25个时,这真的很浪费。

有了这个主意,我们可以做得更好!我们对字符串的第一个字母进行并行化处理,然后使用集合中的七个元素(不包括开头的字母)生成所有排列。这样,我们可以执行26个任务(或52或62),并且仍然使用该算法。看起来可能像这样:

# Use whatever chars you want as the set.
chars = set(string.ascii_lowercase)

# We iterate through all the possible heads. This exact loop will be
# parallelized in the end.
for head in chars:
    # Exclude the head from the set.
    remaining_chars = chars - set(head)

    for tail in itertools.permutations(remaining_chars, 7):
        string = head + ''.join(tail)

        # Store the string in your list/file.

为了利用多个核心,我们使用一个池。为此,我们首先需要一个映射函数。这只是上面的重构:

def make_strings(head):
    remaining_chars = chars - set(head)
    strings = [
        head + ''.join(tail)
        for tail in itertools.permutations(remaining_chars, 7)]

    return strings

现在我们可以在其他地方创建一个池,并将其映射到头上:

with multiprocessing.Pool() as pool:
    all_strings = pool.map(make_strings, chars)

在Python 3中,该池仅具有所需的__enter____exit__属性,因此我假设我们使用了该属性。

完成后,将列表列表展平为简单的字符串列表:

strings = [
    string
    for sub_list in all_strings
    for string in sub_list]

由于26是16个核的奇数,我们可以考虑使用itertools.permutation(remaining_chars, 2)创建磁头,然后使用设置的减法生成最后6位数字。


这是Python 3的完整工作脚本,其中总结了所有内容:

import itertools
import multiprocessing
import string


chars = set(string.ascii_lowercase)


def make_strings(head):
    remaining_chars = chars - set(head)
    strings = [
        head + ''.join(tail)
        for tail in itertools.permutations(remaining_chars, 3)]

    return strings


def main():
    with multiprocessing.Pool() as pool:
        all_strings = pool.map(make_strings, chars)

    strings = [
        string
        for sub_list in all_strings
        for string in sub_list]

    print(strings[:100])


if __name__ == '__main__':
    main()