#python #python-3.x #multiprocessing
Вопрос:
Я пытаюсь узнать, как python обрабатывает многопроцессорную обработку, и следовал учебнику youtube для некоторого базового кода, но теперь я сам пытаюсь реализовать компьютер ProcessPoolExecutor.
У меня есть следующий код, который вызывает проблему:
with concurrent.futures.ProcessPoolExecutor() as executor:
results = executor.map(func, sets, repeat(testNumbers))
for result in results:
print(result)
где функция func принимает набор, который представляет собой список наборов и игр-списков (которые я хочу передавать каждый раз, я думаю, что сделал это правильно, используя повтор, это 2d-список целых чисел) , и возвращает словарь.
Когда я запускаю этот код, я получаю ошибку: объект int не может быть повторен, что следует из этапа печати в коде.
Есть ли другой способ, которым я должен получать результаты?
Это небольшой фрагмент кода, который воспроизводит ошибку
import itertools
import concurrent.futures
from itertools import repeat
def singleGameWinner(game, playedNumbers):
if(set(playedNumbers).issubset(set(game))):
return True
else:
return False
def getPowerSet(listOfNumbers, length):
powerset = itertools.combinations(listOfNumbers, length)
return list(set(powerset))
def sortDict(unsorted):
sortedDict = sorted(unsorted, key = lambda i: i['Games Ago'], reverse=True)
return sortedDict
def getWinners(games, sets):
results=[]
for i in range(len(sets)):
count = 0
gamesAgo = -1
for j in reversed(range(len(games))):
if(singleGameWinner(games[j], sets[i])):
count = 1
drawNumber = games[j][1]
gamesAgo = games[j][0]
# gamesAgo = finalDataNumber-gamesAgo
results.append({
"Set": sets[i],
"Wins": int(count),
"Games Ago": int(gamesAgo),
"Draw Number": int(drawNumber)
})
return sortDict(results)
def getRecentWinners(sets, games):
finalDataNumber = games[-1][0]
results = []
for i in range(len(sets)):
count = len(games)
gamesAgo = -1
foundGame = False
while(not foundGame and count > 0):
count -= 1
if(singleGameWinner(games[count], sets[i])):
foundGame = True
gamesAgo = games[count][0]
drawNumber = games[count][1]
gamesAgo = finalDataNumber-gamesAgo
results.append({
"Set": sets[i],
"Games Ago": int(gamesAgo),
"Draw Number": int(drawNumber)
})
return sortDict(results)
def main():
listOfGames = [x for x in range(1,22)]
testNumbers = [1,2]
sets = getPowerSet(testNumbers, 2)
with concurrent.futures.ProcessPoolExecutor() as executor:
results = executor.map(getRecentWinners, sets, repeat(listOfGames))
for result in results:
print(result)
if __name__ == '__main__':
main()
Ответ №1:
Фактическое значение , передаваемое в качестве второго аргумента getRecentWinners
, равно is listOfGames
, которое в качестве значения [1, 2, 3 ... 21]
. Но первая строка getRecentWinners
этого:
def getRecentWinners(sets, games):
finalDataNumber = games[-1][0] # this is the line throwing the exception
Но трассировка стека показывает это, если вы посмотрите внимательно:
concurrent.futures.process._RemoteTraceback:
"""
Traceback (most recent call last):
File "C:Program FilesPython38libconcurrentfuturesprocess.py", line 239, in _process_worker
r = call_item.fn(*call_item.args, **call_item.kwargs)
File "C:Program FilesPython38libconcurrentfuturesprocess.py", line 198, in _process_chunk
return [fn(*args) for args in chunk]
File "C:Program FilesPython38libconcurrentfuturesprocess.py", line 198, in <listcomp>
return [fn(*args) for args in chunk]
File "C:Boobootesttest.py", line 39, in getRecentWinners
finalDataNumber = games[-1][0]
TypeError: 'int' object is not subscriptable
"""
The above exception was the direct cause of the following exception:
Traceback (most recent call last):
File "C:Boobootesttest.py", line 69, in <module>
main()
File "C:Boobootesttest.py", line 65, in main
for result in results:
File "C:Program FilesPython38libconcurrentfuturesprocess.py", line 484, in _chain_from_iterable_of_lists
for element in iterable:
File "C:Program FilesPython38libconcurrentfutures_base.py", line 611, in result_iterator
yield fs.pop().result()
File "C:Program FilesPython38libconcurrentfutures_base.py", line 439, in result
return self.__get_result()
File "C:Program FilesPython38libconcurrentfutures_base.py", line 388, in __get_result
raise self._exception
TypeError: 'int' object is not subscriptable
Но чтобы ответить на ваш вопрос «Есть ли другой способ, которым я должен получать результаты?», совсем не ясно, чего вы пытаетесь достичь. Очевидно, что рассматривать целое число (в данном случае 21) так, как если бы оно было чем-то, на что можно подписаться, не имеет смысла. Итак, вы хотели передать что-то еще или вы хотели не подписываться на это? Кроме того, у вас есть следующий код:
def getPowerSet(listOfNumbers, length):
powerset = itertools.combinations(listOfNumbers, length)
return list(set(powerset))
Вы вызываете эту функцию с аргументом listOfNumbers , указанным как [1, 2]
, и длиной, указанной как 2
, которая является длиной списка. Будет ли второй аргумент всегда иметь длину первого аргумента? Если это так, то, если мы пройдем через вычисления, выполняемые этой функцией, мы получим:
>>> import itertools
>>> listOfNumbers = [1, 2]
>>> length = 2
>>> powerset = itertools.combinations(listOfNumbers, length)
>>> s = set(powerset)
>>> s
{(1, 2)}
>>> list(s)
[(1, 2)]
Когда вы вызываете combinations
функцию против списка чисел и передаете в качестве второго аргумента длину этого списка, есть только один способ, которым вы можете принимать N элементов N за раз. Таким образом, все, что у вас получается, — это кортеж исходного списка чисел. Затем, когда вы передаете этот кортеж в качестве аргумента set
конструктору, вы получаете набор с одним элементом, а именно кортеж. Наконец, затем вы создаете список, передаваемый как итеративный набор, так что все, что вам удалось создать, — это список с одним кортежем. Вся эта функция могла быть перекодирована как:
def getPowerSet(listOfNumbers):
return [tuple(listOfNumbers)]
Это не могло быть тем, что ты имел в виду.
Даже если второй аргумент не будет иметь длину первого аргумента (предположительно меньшее значение), combinations
он даст уникальные кортежи. Итак, в чем смысл первого создания набора из этих значений перед созданием списка? Это имело бы смысл только в том случае, если бы вам сначала нужно было удалить повторяющиеся значения.
Еще один Способ Избежать повторения
Вы могли бы сделать игры первым аргументом для getRecentWinners
:
from functools import partial
def getRecentWinners(games, sets):
... # etc.
А затем вызовите map
следующим образом:
def main():
listOfGames = [x for x in range(1,22)]
testNumbers = [1,2]
sets = getPowerSet(testNumbers, 2)
with concurrent.futures.ProcessPoolExecutor() as executor:
results = executor.map(partial(getRecentWinners, listOfGames), sets)
... # etc.
Обновить
Итак, теперь, чтобы избавиться от исходного исключения, вы составляете listOfGames
список списков, например:
listOfGames = [[x for x in range(1,22)]]
(Но теперь вам действительно следует обновить свой вопрос с помощью обновленного источника, включая и новую трассировку стека), которая:
concurrent.futures.process._RemoteTraceback:
"""
Traceback (most recent call last):
File "C:Program FilesPython38libconcurrentfuturesprocess.py", line 239, in _process_worker
r = call_item.fn(*call_item.args, **call_item.kwargs)
File "C:Program FilesPython38libconcurrentfuturesprocess.py", line 198, in _process_chunk
return [fn(*args) for args in chunk]
File "C:Program FilesPython38libconcurrentfuturesprocess.py", line 198, in <listcomp>
return [fn(*args) for args in chunk]
File "C:Rontesttest.py", line 47, in getRecentWinners
if(singleGameWinner(games[count], sets[i])):
File "C:Rontesttest.py", line 6, in singleGameWinner
if(set(playedNumbers).issubset(set(game))):
TypeError: 'int' object is not iterable
"""
The above exception was the direct cause of the following exception:
Traceback (most recent call last):
File "C:Rontesttest.py", line 69, in <module>
main()
File "C:Rontesttest.py", line 65, in main
for result in results:
File "C:Program FilesPython38libconcurrentfuturesprocess.py", line 484, in _chain_from_iterable_of_lists
for element in iterable:
File "C:Program FilesPython38libconcurrentfutures_base.py", line 611, in result_iterator
yield fs.pop().result()
File "C:Program FilesPython38libconcurrentfutures_base.py", line 439, in result
return self.__get_result()
File "C:Program FilesPython38libconcurrentfutures_base.py", line 388, in __get_result
raise self._exception
TypeError: 'int' object is not iterable
Таким образом, строка 6 выбрасывает исключение:
def singleGameWinner(game, playedNumbers):
if(set(playedNumbers).issubset(set(game))): # this line is the problem
return True
else:
return False
Поэтому мы вставляем новую первую строку в эту функцию, чтобы распечатать входные аргументы, и мы видим, что происходит:
def singleGameWinner(game, playedNumbers):
print('game =', game, 'playedNumbers =', playedNumbers)
if(set(playedNumbers).issubset(set(game))):
return True
else:
return False
И это печатает:
game = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21] playedNumbers = 1
Таким образом, проблема заключается в выражении set(playedNumbers)
, потому set
что конструктору требуется итерируемое, такое как a list
, и здесь вы передаете одно int
.
Комментарии:
1. Спасибо вам за ваш ответ, за то, что ответили на ваши вопросы. listOfGames — это список списков, содержащих целые числа (представляющие игры кено, если вы знакомы), и я пытаюсь. Ибо
getPowerSet
длинаlistOfNumbers
будет меняться по мере увеличения длины. В целом я просто пытаюсь запустить несколько процессовgetRecentWinners
, чтобы ускорить вычисления для больших наборовlistOfGames
, а такжеsets
.2. Прояснил ли мой ответ что-нибудь для вас относительно вашей проблемы? И да
length
, второй аргумент togetPowerSet
будет меняться , но если он всегда меняется так, что равен длине первого аргумента, это не имеет смысла. И для этого нет причинreturn list(set(powerset))
; так и должно бытьreturn list(powerset)
.3. Да, ваш ответ прояснил некоторые вещи, однако после изменения
listOfGames
на список списков ошибка теперьint is not iterable
. После прочтения трассировки стека она выделяетсяif(singleGameWinner(games[count], sets[i])):
иif(set(playedNumbers).issubset(set(game))):
не имеет итераций. Чтобы воспроизвести эту ошибку, вам просто нужно составитьlistOfGames
список списков.4. Смотрите мой обновленный ответ. Это базовая отладка: вам нужно просмотреть трассировку стека, чтобы определить, где в вашем источнике вы получаете ошибку, а затем вставить инструкции печати, чтобы при необходимости просмотреть значения.