Ошибка ProcessPoolExecutor, Int не может быть повторен/подписан

#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 , второй аргумент to getPowerSet будет меняться , но если он всегда меняется так, что равен длине первого аргумента, это не имеет смысла. И для этого нет причин 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. Смотрите мой обновленный ответ. Это базовая отладка: вам нужно просмотреть трассировку стека, чтобы определить, где в вашем источнике вы получаете ошибку, а затем вставить инструкции печати, чтобы при необходимости просмотреть значения.