Многопроцессор python vs threading для работы cpu для работы с окнами и linux

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

linux (dual quad core xeon):
serialrun took 1192.319 ms
parallelrun took 346.727 ms
threadedrun took 2108.172 ms

Мой двухъядерный macbook pro показывает такое же поведение:

osx (dual core macbook pro)
serialrun took 2026.995 ms
parallelrun took 1288.723 ms
threadedrun took 5314.822 ms

Затем я пошел и попробовал его на машине с Windows и получил очень разные результаты.

windows (i7 920):
serialrun took 1043.000 ms
parallelrun took 3237.000 ms
threadedrun took 2343.000 ms

Почему, почему, многопроцессорный подход намного медленнее на окнах?

Здесь тестовый код:

#!/usr/bin/env python

import multiprocessing
import threading
import time

def print_timing(func):
    def wrapper(*arg):
        t1 = time.time()
        res = func(*arg)
        t2 = time.time()
        print '%s took %0.3f ms' % (func.func_name, (t2-t1)*1000.0)
        return res
    return wrapper


def counter():
    for i in xrange(1000000):
        pass

@print_timing
def serialrun(x):
    for i in xrange(x):
        counter()

@print_timing
def parallelrun(x):
    proclist = []
    for i in xrange(x):
        p = multiprocessing.Process(target=counter)
        proclist.append(p)
        p.start()

    for i in proclist:
        i.join()

@print_timing
def threadedrun(x):
    threadlist = []
    for i in xrange(x):
        t = threading.Thread(target=counter)
        threadlist.append(t)
        t.start()

    for i in threadlist:
        i.join()

def main():
    serialrun(50)
    parallelrun(50)
    threadedrun(50)

if __name__ == '__main__':
    main()

Ответы

Ответ 1

Процессы намного более легкие в вариантах UNIX. Процессы Windows тяжелы и требуют гораздо больше времени для запуска. Темы - рекомендуемый способ многопроцессорности в Windows.

Ответ 2

Документация python для многопроцессорности винит в отсутствии os.fork() проблемы в Windows. Он может быть применим здесь.

Посмотрите, что произойдет, когда вы импортируете psyco. Во-первых, easy_install it:

C:\Users\hughdbrown>\Python26\scripts\easy_install.exe psyco
Searching for psyco
Best match: psyco 1.6
Adding psyco 1.6 to easy-install.pth file

Using c:\python26\lib\site-packages
Processing dependencies for psyco
Finished processing dependencies for psyco

Добавьте это в начало вашего python script:

import psyco
psyco.full()

Я получаю эти результаты без:

serialrun took 1191.000 ms
parallelrun took 3738.000 ms
threadedrun took 2728.000 ms

Я получаю следующие результаты:

serialrun took 43.000 ms
parallelrun took 3650.000 ms
threadedrun took 265.000 ms

Параллельно все еще медленно, но остальные сжигают резину.

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

@print_timing
def parallelpoolrun(reps):
    pool = multiprocessing.Pool(processes=4)
    result = pool.apply_async(counter, (reps,))

Результаты:

C:\Users\hughdbrown\Documents\python\StackOverflow>python  1289813.py
serialrun took 57.000 ms
parallelrun took 3716.000 ms
parallelpoolrun took 128.000 ms
threadedrun took 58.000 ms

Ответ 3

Было сказано, что создание процессов в Windows дороже, чем на Linux. Если вы ищете по сайту, вы найдете некоторую информацию. Здесь один я нашел легко.

Ответ 4

В настоящее время ваша функция counter() не модифицирует много состояний. Попробуйте изменить счетчик(), чтобы он изменял многие страницы памяти. Затем запустите cpu bound loop. Посмотрите, есть ли еще большое несоответствие между linux и окнами.

Я не запускаю python 2.6 прямо сейчас, поэтому сам не могу попробовать.

Ответ 5

Простое начало пула занимает много времени. Я нашел в программах "реального мира", если я могу оставить пул открытым и повторно использовать его для многих разных процессов, передав ссылку через вызовы методов (обычно используя map.async), а затем в Linux я могу сэкономить несколько процентов, но в Windows Я часто могу сократить вдвое время. Linux всегда быстрее для моих конкретных проблем, но даже в Windows я получаю чистые преимущества от многопроцессорности.