我正在尝试找出是否可以加快排列的产生。具体来说,我要在[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上运行,然后加入结果,那就太好了。
答案 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()