Если бы это были просто перестановки с заменой , это было бы очень просто: просто распараллелить первую букву строки и затем позволить каждому потоку добавить хвост строки. Это даст вам 26 независимых задач. Если этого недостаточно, вы можете распараллелить первые две буквы.
Вы хотите иметь перестановку без замены , поэтому проблема не является тривиальной факторизацией. Если нужно выбрать только 8 букв из набора 26, 52 и 62, можно сделать наивную грубую вещь: распараллелить первую букву, позволить потоку просто создать хвост с заменой и отбросить сгенерированные строки, содержащие дубликаты. Но если вы хотите выбрать 25 из 26 букв, это становится действительно расточительным.
Учитывая эту идею, мы можем добиться большего! Мы распараллеливаем первую букву строки и затем генерируем все перестановки с семью элементами из набора, исключая букву, с которой мы начали. Таким образом, мы можем иметь 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)
Пул получил только необходимые свойства __enter__
и __exit__
с Python 3, поэтому я предполагаю, что мы используем это.
Как только это будет сделано, сведите список списков в простой список строк:
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()