Кажется, что python сначала сгенерировал список аргументов, а затем передал список функции «f», даже используя xrange. Это верно?
Да, потому что вы используете понимание списка, которое явно просит его сгенерировать этот список.
(Обратите внимание, что xrange
не очень уместная здесь, потому что у вас есть только два диапазона, в то время, каждый 10K долго, по сравнению с 100M списком аргументов, что нет ничего.)
Если вы хотите для генерации значений «на лету» по мере необходимости, вместо всего 100M сразу, вы хотите использовать выражение генератора вместо понимания списка. Что почти всегда только вопрос поворота скобки в скобках:
x=pool.map(f,((i,j) for i in range(10000) for j in range(10000)))
Однако, как вы можете видеть из the source, map
, в конечном счете просто составить список, если вы даете ему генератор, так что в этом случай, который ничего не решит. (Документы явно не говорят об этом, но трудно понять, как он может выбрать хороший chunksize, чтобы нарезать итерируемый, если он не имеет длины ...).
И даже если это не так, вы все равно снова столкнетесь с той же проблемой с результатами, потому что pool.map
возвращает список.
Для решения обеих проблем вы можете использовать pool.imap
. Он потребляет итерируемый лениво и возвращает ленивый итератор результатов.
Одна вещь, чтобы отметить, что imap
не догадывается, в лучшем случае chunksize, если вы не разъехаться, но только по умолчанию 1
, так что вам может понадобиться немного мысли или суда & ошибки, чтобы оптимизировать его.
Кроме того, imap
по-прежнему будет стоять в очереди на некоторые результаты по мере их поступления, чтобы он мог вернуть их обратно в том же порядке, что и аргументы. В патологических случаях он может оказаться в очереди (пул-1)/объединить ваши результаты, хотя на практике это невероятно редко.Если вы хотите решить эту проблему, используйте imap_unordered
. Если вам необходимо знать порядок, просто передать индексы назад и вперед с арг и результатами:
args = ((i, j) for i in range(10000) for j in range(10000))
def indexed_f(index, (i, j)):
return index, f(i, j)
results = pool.imap_unordered(indexed_f, enumerate(args))
Однако я заметил, что в исходном коде, вы ничего не делать вообще с результаты f(i, j)
. В таком случае, зачем вообще собирать результаты? В этом случае, вы можете просто вернуться к петле:
for i in range(10000):
for j in range(10000):
map.apply_async(f, (i,j))
Однако imap_unordered
все еще может быть стоит использовать, так как она обеспечивает очень простой способ, чтобы блокировать, пока все задачи выполняются, в то же время оставляя сам пул для последующего использования:
def consume(iterator):
deque(iterator, max_len=0)
x=pool.imap_unordered(f,((i,j) for i in range(10000) for j in range(10000)))
consume(x)
Вкратце: это не имеет никакого смысла, поскольку Python использует глобальную блокировку интерпретатора, которая предотвращает одновременное выполнение нескольких потоков. Вы все равно можете воспользоваться некоторыми преимуществами, если используете Jython или IronPython. http://wiki.python.org/moin/GlobalInterpreterLock –
@GiulioFranco. Он использует «многопроцессорность», хотя и не «threading», поэтому GIL не играет. –