Подтвердить что ты не робот

Python Многопроцессорный процесс или пул для того, что я делаю?

Я новичок в многопроцессорности на Python и пытаюсь выяснить, должен ли я использовать Pool или Process для вызова двух функций async. Две функции, которые я выполняю, вызывают завихрения и анализируют информацию в 2 отдельных списках. В зависимости от подключения к Интернету каждая функция может занимать около 4 секунд. Я понимаю, что узкое место находится в соединении с ISP, и многопроцессорность не ускорит его, но было бы неплохо, если бы они оба начали асинхронный запуск. Кроме того, это отличный опыт для меня, чтобы перейти на многопроцессорную обработку python, потому что я буду использовать его более позднее.

Я прочитал многопроцессор Python.Pool: когда использовать apply, apply_async или карту?, и это было полезно, но у меня все же были свои вопросы.

Таким образом, один из способов сделать это:

def foo():
    pass

def bar():
    pass

p1 = Process(target=foo, args=())
p2 = Process(target=bar, args=())

p1.start()
p2.start()
p1.join()
p2.join()

Вопросы, которые у меня есть для этой реализации: 1) Поскольку блоки объединения до завершения процесса вызова завершены... означает ли это, что процесс p1 должен завершиться до того, как начнется процесс p2? Я всегда понимал, что .join() будет таким же, как pool.apply() и pool.apply_sync(). Get(), когда родительский процесс не может запустить другой процесс (задачу) до тех пор, пока не будет выполнен текущий текущий.

Другим вариантом будет что-то вроде:

def foo():
    pass

def bar():
    pass
pool = Pool(processes=2)             
p1 = pool.apply_async(foo)
p1 = pool.apply_async(bar)

Вопросы, которые у меня есть для этой реализации, будут: 1) Нужен ли мне pool.close(), pool.join()? 2) Будет ли pool.map() сделать их полностью законченными, прежде чем я смогу получить результаты? И если да, то они все еще бегут асинч? 3) Как pool.apply_async() отличается от выполнения каждого процесса с помощью pool.apply() 4) Как это отличается от предыдущей реализации процессом?

4b9b3361

Ответ 1

Два перечисленных вами сценария выполняют одно и то же, но несколько разными способами.

Первый сценарий запускает два отдельных процесса (называет их P1 и P2) и запускает P1 с запуском foo и P2 работает bar, а затем ждет, пока оба процесса не закончат свои соответствующие задачи.

Второй сценарий запускает два процесса (называет их Q1 и Q2) и сначала запускает foo на Q1 или Q2, а затем запускает bar на Q1 или Q2. Затем код ждет, пока оба вызова функций не вернутся.

Таким образом, чистый результат на самом деле тот же, но в первом случае вы гарантированно выполняете foo и bar для разных процессов.

Что касается конкретных вопросов, которые вы имели о concurrency, метод .join() на Process действительно блокируется до тех пор, пока процесс не завершится, а потому, что вы вызвали .start() на P1 и P2 (в первом сценарий) перед присоединением, то оба процесса будут выполняться асинхронно. Однако интерпретатор ждет, пока P1 не закончит работу до того, как будет ждать завершения P2.

Для ваших вопросов о сценарии пула вы должны технически использовать pool.close(), но это зависит от того, что вам может понадобиться для последующего (если он просто выходит из сферы, то вам не нужно обязательно его закрывать), pool.map() - совершенно другой вид животного, потому что он распределяет кучу аргументов одной и той же функции (асинхронно), через процессы пула, а затем ждет, пока все вызовы функций не будут завершены, прежде чем возвращать список результатов.

Ответ 2

Поскольку вы извлекаете данные из локонных вызовов, вы привязаны к IO. В таком случае grequests может пригодиться. На самом деле это ни процессы, ни потоки, но сопрограммы - легкие потоки. Это позволит вам отправлять асинхронно HTTP-запросы, а затем использовать multiprocessing.Pool для ускорения части, связанной с процессором.

1) Поскольку блоки объединения до завершения процесса вызова завершены... означает ли это, что процесс p1 должен завершиться до того, как начнется процесс p2?

Да, p2.join() вызывается после того, как p1.join() вернул значение p1.

1) Нужен ли мне pool.close(), pool.join()

Возможно, вы закончите с потерянными процессами, не делая close() и join() (если процессы выполняются неопределенно)

2) Будет ли метод pool.map() сделать их полностью законченными, прежде чем я смогу получить результаты? И если так, они все еще запускают асинхронный?

Они запускаются асинхронно, но map() блокируется до тех пор, пока не будут выполнены все задачи.

3) Как бы pool.apply_async() отличался от выполнения каждого процесса с помощью pool.apply()

pool.apply() блокируется, поэтому в основном вы будете обрабатывать синхронно.

4) Как это будет отличаться от предыдущей реализации с Process

Скорее всего, рабочий делается с помощью foo, прежде чем применять bar, чтобы вы могли закончить с одним работником, выполняющим всю работу. Кроме того, если один из ваших рабочих умирает Pool автоматически создает новую (вам нужно будет повторно применить задачу).

Подводя итог: я бы предпочел пойти с Pool - он идеально подходит для случаев производителей-потребителей и заботится обо всей логике распределения задач.