Привет, Алин, и добро пожаловать в stackoverflow.
Во-первых, да, глобальный счетчик возможен .Например, с многопроцессорной обработкой . Queue или многопроцессорной обработкой . Значение , которое передается рабочим.Однако выбор нового номера из глобального счетчика приведет к блокировке (и, возможно, ожиданию) счетчика.Этого можно и нужно избегать, так как вам нужно сделать МНОГО встречных запросов.Мое предлагаемое ниже решение позволяет избежать глобального счетчика, установив несколько локальных счетчиков, которые работают вместе, как если бы они были одним глобальным счетчиком.
Что касается потребления ОЗУ вашего кода, я вижу две проблемы:
computesha
возвращает значение None
большую часть времени.Это входит в итератор, который создается map
(даже если вы не присваиваете возвращаемое значение map
).Это означает, что итератор намного больше необходимого. - Вообще говоря, ОЗУ процесса освобождается после его завершения.Ваши процессы запускают множество задач, которые все резервируют свою собственную память.Возможное решение - опция
maxtasksperchild
(см. Документацию multiprocessing.pool.Pool ).Когда вы устанавливаете эту опцию на 1000, она закрывает процесс после 1000 задач и создает новую, которая освобождает память.
Однако я хотел бы предложить другое решение, которое решает обе проблемы, очень дружественный к памяти и работает быстрее (как мне кажется после N <10 тестов) как решение с опцией <code>maxtasksperchild:
#!/usr/bin/env python3
import datetime
import multiprocessing
import hashlib
import sys
def computesha(process_number, number_of_processes, max_counter, results):
counter = process_number # every process starts with a different counter
data = 'somedata' + 'otherdata'
while counter < max_counter: #stop after max_counter jobs have been started
hash = "".join((data,str(counter)))
newHash = hashlib.sha1(hash.encode()).hexdigest()
if newHash[:9] == '000000000':
print(str(newHash))
print(str(counter))
# return the results through a queue
results.put((str(newHash), str(counter)))
counter += number_of_processes # 'jump' to the next chunk
if __name__ == '__main__':
# execute this file with two command line arguments:
number_of_processes = int(sys.argv[1])
max_counter = int(sys.argv[2])
# this queue will be used to collect the results after the jobs finished
results = multiprocessing.Queue()
processes = []
# start a number of processes...
for i in range(number_of_processes):
p = multiprocessing.Process(target=computesha, args=(i,
number_of_processes,
max_counter,
results))
p.start()
processes.append(p)
# ... then wait for all processes to end
for p in processes:
p.join()
# collect results
while not results.empty():
print(results.get())
results.close()
Этот код порождает желаемый number_of_processes
, который затемвызовите функцию computesha
.Если number_of_processes=8
, то первый процесс вычисляет хэш для значений счетчика [0,8,16,24,...]
, второй процесс для [1,9,17,25]
и т. Д.
Преимущества этого подхода: в каждой итерации цикла whileпамять hash
и newHash
можно использовать повторно, циклы дешевле, чем функции, и необходимо выполнять только number_of_processes
вызовы функций, а неинтересные результаты просто забываются.
Возможный недостаток состоит в том, чточто счетчики полностью независимы, и каждый процесс будет выполнять ровно 1/number_of_processes
всей работы, даже если некоторые из них быстрее, чем другие.В конце концов, программа работает так же быстро, как самый медленный процесс.Я не измерял это, но я полагаю, что это довольно теоретическая проблема.
Надеюсь, это поможет!