Какая разница между ThreadPool и Pool в модуле многопроцессорности Python

В чем разница между ThreadPool и Pool в модуле multiprocessing. Когда я пытаюсь выполнить код, это основное различие, которое я вижу:

from multiprocessing import Pool
import os, time

print("hi outside of main()")

def hello(x):
    print("inside hello()")
    print("Proccess id: ", os.getpid())
    time.sleep(3)
    return x*x

if __name__ == "__main__":
    p = Pool(5)
    pool_output = p.map(hello, range(3))

    print(pool_output)

Я вижу следующий вывод:

hi outside of main()
hi outside of main()
hi outside of main()
hi outside of main()
hi outside of main()
hi outside of main()
inside hello()
Proccess id:  13268
inside hello()
Proccess id:  11104
inside hello()
Proccess id:  13064
[0, 1, 4]

С "ThreadPool":

from multiprocessing.pool import ThreadPool
import os, time

print("hi outside of main()")

def hello(x):
    print("inside hello()")
    print("Proccess id: ", os.getpid())
    time.sleep(3)
    return x*x

if __name__ == "__main__":
    p = ThreadPool(5)
    pool_output = p.map(hello, range(3))

    print(pool_output)

Я вижу следующий вывод:

hi outside of main()
inside hello()
inside hello()
Proccess id:  15204
Proccess id:  15204
inside hello()
Proccess id:  15204
[0, 1, 4]

Мои вопросы:

  • почему "внешний __main __()" запускается каждый раз в Pool?

  • multiprocessing.pool.ThreadPool не порождает новые процессы? Он просто создает новые потоки?

  • Если да, то в чем разница между использованием multiprocessing.pool.ThreadPool, а не только с модулем threading?

Я не вижу никакой официальной документации для ThreadPool в любом месте, может кто-нибудь помочь мне, где я могу ее найти?

Ответ 1

multiprocessing.pool.ThreadPool ведет себя так же, как multiprocessing.Pool, с той лишь разницей, что для выполнения рабочей логики используются потоки, а не процессы.

Причина, по которой вы видите

hi outside of main()

печатается несколько раз с multiprocessing.Pool из-за того, что пул порождает 5 независимых процессов. Каждый процесс инициализирует свой собственный интерпретатор Python и загружает модуль, в результате чего верхний уровень print выполняется снова.

Обратите внимание, что это происходит, только если используется метод создания процесса spawn (только метод, доступный в Windows). Если вы используете fork (Unix), вы увидите сообщение, напечатанное только один раз, как для потоков.

multiprocessing.pool.ThreadPool не задокументирован, так как его реализация никогда не была завершена. Не хватает тестов и документации. Вы можете увидеть его реализацию в исходном коде.

Я считаю, что следующий естественный вопрос: когда использовать пул, основанный на потоках, а когда пул, основанный на процессах?

Основное правило:

  • IO связанные задания → multiprocessing.pool.ThreadPool
  • Связанные с CPU задания → multiprocessing.Pool
  • Гибридные задания → зависит от рабочей нагрузки, я обычно предпочитаю multiprocessing.Pool из-за преимущества, которое дает изоляция процесса

В Python 3 вы можете взглянуть на реализации пула concurrent.future.Executor.