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

Использование 100% всех ядер с многопроцессорным модулем

У меня есть две части кода, которые я использую, чтобы узнать о многопроцессорности в Python 3.1. Моя цель - использовать 100% всех доступных процессоров. Тем не менее, фрагменты кода здесь достигают только 30% - 50% на всех процессорах.

Есть ли какой-либо способ заставить "питона" использовать все 100%? ОС (Windows 7, 64bit) ограничивает доступ Python к процессорам? Пока выполняются приведенные ниже фрагменты кода, я открываю диспетчер задач и наблюдаю всплеск процессора, но никогда не достигаю и не поддерживаю 100%. В дополнение к этому, я вижу несколько процессов python.exe, созданных и уничтоженных по пути. Как эти процессы связаны с процессорами? Например, если я порождаю 4 процесса, каждый процесс не использует свое собственное ядро. Вместо этого, какие процессы используют? Они разделяют все ядра? И если так, то ОС заставляет процессы делить ядра?

фрагмент кода 1

import multiprocessing

def worker():
    #worker function
    print ('Worker')
    x = 0
    while x < 1000:
        print(x)
        x += 1
    return

if __name__ == '__main__':
    jobs = []
    for i in range(50):
        p = multiprocessing.Process(target=worker)
        jobs.append(p)
        p.start()

фрагмент кода 2

from multiprocessing import Process, Lock

def f(l, i):
    l.acquire()
    print('worker ', i)
    x = 0
    while x < 1000:
        print(x)
        x += 1
    l.release()

if __name__ == '__main__': 
    lock = Lock()
    for num in range(50):
        Process(target=f, args=(lock, num)).start()
4b9b3361

Ответ 1

Чтобы использовать 100% всех ядер, не создавайте и не уничтожайте новые процессы.

Создайте несколько процессов на ядро ​​и привяжите их к конвейеру.

На уровне ОС все конвейерные процессы запускаются одновременно.

Чем меньше вы пишете (и чем больше вы делегируете ОС), тем более вероятно, что вы должны использовать как можно больше ресурсов.

python p1.py | python p2.py | python p3.py | python p4.py ...

Максимально использовать ваш процессор.

Ответ 2

Вы можете использовать psutil для psutil каждого процесса, порожденного multiprocessing на конкретном процессоре:

import multiprocessing as mp
import psutil


def spawn():
    procs = list()
    n_cpus = psutil.cpu_count()
    for cpu in range(n_cpus):
        affinity = [cpu]
        d = dict(affinity=affinity)
        p = mp.Process(target=run_child, kwargs=d)
        p.start()
        procs.append(p)
    for p in procs:
        p.join()
        print('joined')

def run_child(affinity):
    proc = psutil.Process()  # get self pid
    print('PID: {pid}'.format(pid=proc.pid))
    aff = proc.cpu_affinity()
    print('Affinity before: {aff}'.format(aff=aff))
    proc.cpu_affinity(affinity)
    aff = proc.cpu_affinity()
    print('Affinity after: {aff}'.format(aff=aff))


if __name__ == '__main__':
    spawn()

Примечание. Как прокомментировано, psutil.Process.cpu_affinity недоступен в macOS.

Ответ 3

Что касается фрагмента кода 1: Сколько ядер/процессоров у вас есть на тестовой машине? Это не поможет вам запустить 50 из этих процессов, если у вас есть только 2 ядра процессора. Фактически вы вынуждаете ОС тратить больше времени на переключение контекста, чтобы переместить процессы в CPU и вне его, чем выполнять фактическую работу.

Попробуйте уменьшить количество порожденных процессов до количества ядер. Итак, "для я в диапазоне (50):" должно стать чем-то вроде:

import os;
# assuming you're on windows:
for i in range(int(os.environ["NUMBER_OF_PROCESSORS"])):
    ...

Что касается фрагмента кода 2: вы используете многопроцессорную систему. Блокировка, которая может поддерживаться только одним процессом за раз, поэтому вы полностью ограничиваете все parallelism в этой версии программы. Вы сериализовали все, чтобы начать процесс с 1 по 50, случайный процесс (например, процесс 7) получает блокировку. Процессы 1-6 и 8-50 все сидят на линии:

l.acquire()

Пока они сидят, они просто ждут выхода блокировки. В зависимости от реализации примитива Lock они, вероятно, не используют какой-либо процессор, они просто сидят там, используя системные ресурсы, такие как RAM, но не выполняют полезную работу с процессором. Процесс 7 подсчитывает и печатает до 1000, а затем освобождает блокировку. Затем ОС может планировать случайным образом один из оставшихся 49 процессов для запуска. Независимо от того, что он просыпается первым, он получит следующий замок и запустится, а оставшиеся 48 ждут блокировки. Это будет продолжаться для всей программы.

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

Итак, из этих двух, Snippet 1 ближе к более эффективному использованию CPU. Я думаю, что правильная настройка количества процессов в соответствии с количеством ядер приведет к значительному улучшению результата.

Ответ 4

Минимальный пример на чистом Python:

def f(x):
    while 1:
        # ---bonus: gradually use up RAM---
        x += 10000  # linear growth; use exponential for faster ending: x *= 1.01
        y = list(range(int(x))) 
        # ---------------------------------
        pass  # infinite loop, use up CPU

if __name__ == '__main__':  # name guard to avoid recursive fork on Windows
    import multiprocessing as mp
    n = mp.cpu_count() * 32  # multiply guard against counting only active cores
    with mp.Pool(n) as p:
        p.map(f, range(n))

Использование: чтобы согреться в холодный день (но не стесняйтесь менять цикл на что-то менее бессмысленное.)

Предупреждение: чтобы выйти, не тяните за вилку и не держите кнопку питания, вместо этого нажмите Ctrl-C.

Ответ 5

Чтобы ответить на ваши вопросы:

В любом случае, чтобы "заставить" python использовать все 100%?

Не то, чтобы я слышал о

Является ли ОС (Windows 7, 64 бит) ограничивающим доступ к процессорам Python?

Да и Нет, Да: если python занимает 100%, окна замерзнут. Нет, вы можете предоставить python Admin Priviledges, что приведет к блокировке.

Как эти процессы относятся к процессорам?

Они не являются технически на уровне ОС, эти "процессы" python - это потоки, которые обрабатываются обработчиком ОС, поскольку он нуждается в обработке.

Вместо этого, какие процессы используют? Разделяют ли они все ядра? И если да, то это ОС, которая вынуждает процессы делиться ядрами?

Они делятся всеми ядрами, если только вы не запустите один экземпляр python с привязкой к определенному ядру (в многоядерной системе) ваши процессы будут разделены на обработку без ведома без обработки. Итак, да, ОС заставляет основной доступ по умолчанию (или python технически)

если вы заинтересованы в сродстве к ядру python, ознакомьтесь с аффилированным пакетом для python.