Я пытался сделать мой код параллельным, и я столкнулся со странной вещью, которую я не в состоянии объяснить.
Позвольте мне определить контекст. У меня действительно тяжелые вычисления: чтение нескольких файлов, анализ машинного обучения, много математики. Мой код работает нормально в Windows и Linux, когда это последовательно, но когда я пытаюсь использовать многопроцессорность, все ломается.
Ниже приведен пример, который я сначала разработал для Windows:
from multiprocessing.dummy import Pool as ThreadPool
def ppp(element):
window,day = element
print(window,day)
time.sleep(5)
return
if __name__ == '__main__'
#%% Reading datasets
print('START')
start_time = current_milli_time()
tree = pd.read_csv('datan\\days.csv')
days = list(tree.columns)
# to be able to run this code uncomment the following line and comment the previous two
# days = ['0808', '0810', '0812', '0813', '0814', '0817', '0818', '0827', '0828', '0829']
windows = [1000]
processes_args = list(itertools.product(windows, days))
pool = ThreadPool(8)
results = pool.map_async(ppp, processes_args)
pool.close()
pool.join()
print('END', current_milli_time()-start_time, 'ms')
Когда я запускаю этот код в Windows, вывод выглядит так:
START
100010001000 1000 1000100010001000 081008120808
08130814
0818
082708171000
1000
08290828
END 5036 ms
Грязный набор отпечатков за 125 мс. Такое же поведение и в Linux. Однако я заметил, что если я применяю этот метод в Linux и смотрю на «htop», я вижу набор потоков, которые выбираются случайным образом для выполнения, но никогда не выполняются параллельно. Таким образом, после некоторых поисков в Google, я получил новый код:
from multiprocessing import Pool as ProcessPool
def ppp(element):
window,day = element
print(window,day)
time.sleep(5)
return
if __name__ == '__main__':
#%% Reading datasets
print('START')
start_time = current_milli_time()
tree = pd.read_csv('datan\\days.csv')
days = list(tree.columns)
# to be able to run this code uncomment the following line and comment the previous two
# days = ['0808', '0810', '0812', '0813', '0814', '0817', '0818', '0827', '0828', '0829']
windows = [1000]
processes_args = list(itertools.product(windows, days))
pool = ProcessPool(8)
results = pool.map_async(ppp, processes_args)
pool.close()
pool.join()
print('END', current_milli_time()-start_time, 'ms')
Как видите, я изменил оператор импорта, который в основном создает пул процессов вместо пула потоков. Это решает проблему в Linux, фактически в реальном сценарии у меня 8 процессоров, работающих на 100%, и 8 процессов, работающих в системе. Вывод выглядит как предыдущий. Тем не менее, когда я использую этот код в Windows, требуется более 10 секунд для всей работы, более того, я не получаю отпечатки ppp
, а только основные.
Я действительно пытался найти объяснение, но я не понимаю, почему это происходит. Например, здесь: Python multiprocessing Pool странное поведение в Windows , они говорят о безопасном коде на окнах, и ответ предлагает перейти к Threading, что, как побочный эффект, сделает код не параллельным, а параллельным , Вот еще один пример: Разница в многопроцессорности Linux Python Windows . Все эти вопросы описывают процессы fork()
и spawn
, но я лично считаю, что смысл моего вопроса не в этом. Документация Python по-прежнему объясняет, что в Windows нет метода fork()
(https://docs.python.org/2/library/multiprocessing.html#programming-guidelines).
В заключение, сейчас я убежден, что я не могу выполнять параллельную обработку в Windows, но я думаю, что то, что я получаю в результате всех этих обсуждений, неверно. Таким образом, у меня должен возникнуть вопрос: возможно ли параллельно запускать процессы или потоки (на разных процессорах) в Windows?
РЕДАКТИРОВАТЬ: добавить имя == main в обоих примерах
EDIT2: чтобы иметь возможность запускать код этой функции и необходим этот импорт:
import time
import itertools
current_milli_time = lambda: int(round(time.time() * 1000))