В целом, вы часто получаете больше пользы от перепроектирования вашего алгоритма, чем от многопроцессорной обработки.
Вот более короткая реализация вашего кода. Я жестко запрограммировал usrList, и, поскольку у меня нет доступа к файлу словаря, который вы используете, я использую файл словаря по умолчанию, который поставляется с MacOS. Вместо того, чтобы писать вложенные циклы и проверять дубликаты индексов, я использую модуль itertools для генерации всех перестановок usrList для заданной длины. Это существенно не ускорит код, но упростит демонстрацию возможных изменений:
import itertools
usrList = ['P', 'Y', 'T', 'H', 'O', 'N', 'S']
storedList = []
with open('/usr/share/dict/words', 'r') as dict_file:
dicList = [word.strip().upper() for word in dict_file]
def possible_words(length):
for letter_permutation in itertools.permutations(usrList, length):
word = ''.join(letter_permutation) # itertools returns a tuple, not a string
if word in dicList: # This requires a linear search through the list
storedList.append(word)
for word_length in range(2, 8): # Note that the upper bound is 7 letters, not 8
possible_words(word_length)
Это займет около 47,4 секунд для запуска на моем Macbook. Чтобы ускорить его, давайте добавим многопроцессорность, как вы предлагаете. Есть несколько способов использовать многопроцессорность, но проще всего реализовать, вероятно, создание пула и вызов его функции map()
.
Этот синтаксис может выглядеть немного странно, если вы не привыкли к функциям, которые принимают другие функции в качестве аргументов. По сути, мы создаем пул работников, затем даем этому пулу функцию и диапазон аргументов для использования в этой функции. Затем отдельные вызовы функций распределяются по пулу вместо последовательного вызова:
import itertools
import multiprocessing
usrList = ['P', 'Y', 'T', 'H', 'O', 'N', 'S']
storedList = []
with open('/usr/share/dict/words', 'r') as dict_file:
dicList = [word.strip().upper() for word in dict_file]
def possible_words(length):
for letter_permutation in itertools.permutations(usrList, length):
word = ''.join(letter_permutation)
if word in dicList:
storedList.append(word)
if __name__ == '__main__': # multiprocessing complains if this isn't isolated
with multiprocessing.Pool(6) as p: # Creates 6 worker processes
p.map(possible_words, range(2, 8)) # Each process calls possible_words() with a different input
Это выполняется за 32.3 секунд на моем Macbook. Мы сбрили четверть времени! Вероятно, есть способы выжать немного больше производительности из этого подхода, но также стоит взглянуть на алгоритм, чтобы увидеть, есть ли другие способы ускорить это.
Прямо сейчас, вы создаете список словарных слов. Когда вы проверяете, есть ли потенциальное слово в этом списке, Python должен просмотреть весь список, пока не найдет совпадение или не достигнет конца. Мой встроенный словарь содержит 235 тыс. Слов, так что это означает, что он должен сравнивать 235 тыс. Строк для каждой бессмысленной комбинации букв, которые он генерирует!
Если вы переключитесь с использования списка на набор, Python может вместо этого ищите значение в почти постоянное время, используя функцию ha sh вместо сканирования каждой записи по одному. Давайте попробуем это вместо многопроцессорной обработки:
import itertools
usrList = ['P', 'Y', 'T', 'H', 'O', 'N', 'S']
storedList = []
with open('/usr/share/dict/words', 'r') as dict_file:
dicSet = {word.strip().upper() for word in dict_file} # By changing [] to {}, this is now a set
def possible_words(length):
for letter_permutation in itertools.permutations(usrList, length):
word = ''.join(letter_permutation)
if word in dicSet: # This now only does 1 check, not 235,000
storedList.append(word)
for word_length in range(2, 8):
possible_words(word_length)
Эта версия запускается за 0,005 секунд , после замены всего двух символов!
В общем, многопроцессорная обработка является полезным инструментом, но это, вероятно, не должно быть первым, что вы попробуете. Как правило, вы получите гораздо лучшие результаты, если продумаете используемые вами структуры данных и алгоритмы, а также то, где может быть узкое место.