Использование большего количества рабочих процессов, чем есть ядер - PullRequest
0 голосов
/ 04 декабря 2018

В этом примере из PYMOTW приведен пример использования multiprocessing.Pool(), где переданный аргумент processes (количество рабочих процессов) в два раза больше ядер на машине.

pool_size = multiprocessing.cpu_count() * 2

(В противном случае класс по умолчанию будет просто cpu_count().)

Есть ли какое-либо обоснование для этого?Каков эффект создания большего количества рабочих, чем есть основные?Есть ли когда-нибудь повод для этого или, возможно, это потребует дополнительных накладных расходов в неправильном направлении?Мне любопытно, почему он был бы последовательно включен в примеры из того, что я считаю авторитетным сайтом.

В первоначальном тесте это, похоже, немного замедляет работу:

$ python -m timeit -n 25 -r 3 'import double_cpus; double_cpus.main()'
25 loops, best of 3: 266 msec per loop
$ python -m timeit -n 25 -r 3 'import default_cpus; default_cpus.main()'
25 loops, best of 3: 226 msec per loop

double_cpus.py:

import multiprocessing

def do_calculation(n):
    for i in range(n):
        i ** 2

def main():
    with multiprocessing.Pool(
        processes=multiprocessing.cpu_count() * 2,
        maxtasksperchild=2,
    ) as pool:
        pool.map(do_calculation, range(1000))

default_cpus.py:

def main():
    # `processes` will default to cpu_count()
    with multiprocessing.Pool(
        maxtasksperchild=2,
    ) as pool:
        pool.map(do_calculation, range(1000))

Ответы [ 2 ]

0 голосов
/ 04 декабря 2018

Выполнение этого может иметь смысл, если ваша работа не является чисто привязанной к процессору, но также требует некоторого ввода-вывода.

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

Я изменил ваш расчет, чтобы он повторялся в диапазоне 10M, вычисляя условие if и позволяя ему вздремнуть в случае, если оноценивается как True, что случается n_sleep раз.Таким образом, общий сон в sleep_sec_total может быть введен в вычисления.

# default_cpus.py
import time
import multiprocessing


def do_calculation(iterations, n_sleep, sleep_sec):
    for i in range(iterations):
        if i % (iterations / n_sleep) == 0:
            time.sleep(sleep_sec)


def main(sleep_sec_total):

    iterations = int(10e6)
    n_sleep = 100
    sleep_sec = sleep_sec_total / n_sleep
    tasks = [(iterations, n_sleep, sleep_sec)] * 20

    with multiprocessing.Pool(
        maxtasksperchild=2,
    ) as pool:
        pool.starmap(do_calculation, tasks)

# double_cpus.py
...

def main(sleep_sec_total):

    iterations = int(10e6)
    n_sleep = 100
    sleep_sec = sleep_sec_total / n_sleep
    tasks = [(iterations, n_sleep, sleep_sec)] * 20

    with multiprocessing.Pool(
        processes=multiprocessing.cpu_count() * 2,
        maxtasksperchild=2,
    ) as pool:
        pool.starmap(do_calculation, tasks)

Я запустил тест с sleep_sec_total=0 (чисто привязанным к процессору) и с sleep_sec_total=2для обоих модулей.

Результаты с sleep_sec_total=0:

$ python -m timeit -n 5 -r 3 'import default_cpus; default_cpus.main(0)'
5 loops, best of 3: 15.2 sec per loop

$ python -m timeit -n 5 -r 3 'import double_cpus; double_cpus.main(0)'
5 loops, best of 3: 15.2 sec per loop

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

Результаты с sleep_sec_total=2:

$ python -m timeit -n 5 -r 3 'import default_cpus; default_cpus.main(2)'
5 loops, best of 3: 20.5 sec per loop
$ python -m timeit -n 5 -r 3 'import double_cpus; double_cpus.main(2)'
5 loops, best of 3: 17.7 sec per loop

Теперь с добавлением 2 секунд сна в качестве пустышки для I / 0,картина выглядит иначе.Использование вдвое большего количества процессов позволило увеличить скорость примерно на 3 секунды по сравнению со значением по умолчанию.

0 голосов
/ 04 декабря 2018

Если ваша задача связана с вводом / выводом (например, ожидание базы данных, сетевой службы), то создание большего количества потоков, чем процессоров, на самом деле увеличивает вашу пропускную способность.

Это потому, что ваш потокв ожидании ввода-вывода процессор может фактически выполнять работу в других потоках.

Если у вас тяжелая задача ЦП, то большее количество процессоров замедлит ее.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...