Пробую multiprocessing в Python 3 | Блог python программиста
Изображение гика

Блог питониста

Пробую multiprocessing в Python 3

8 мая 2020 г.

Недавно потребовалось немного познакомиться с модулем multiprocessing, в этом посте немного опишу свой опыт, попробую начать с базового примера, который дается в документации. Использовать буду, конечно, Python 3.

Итак, базовый пример из документации выглядит так:

1from multiprocessing import Process
2
3def f(name):
4    print('hello', name)
5
6if __name__ == '__main__':
7    p = Process(target=f, args=('bob',))
8    p.start()
9    p.join()

Запустим:

hello bob

Попробую создать несколько процессов:

 1from multiprocessing import Process
 2
 3
 4def f(name):
 5    print('hello', name)
 6
 7
 8if __name__ == '__main__':
 9    for name in ('alex', 'test', 'bob'):
10        p = Process(target=f, args=(name,))
11        p.start()
12        p.join()

После запуска:

hello alex
hello test
hello bob

Хорошо, но что если, я хочу запустить несколько процессов и затем сформировать один массив из данных? В этом может помочь такая штука как Queue, примерно так:

 1from multiprocessing import Process, Queue
 2
 3
 4def f(name, q):
 5    for i in range(3):
 6        q.put(('hello_{0}'.format(i), name))
 7
 8
 9if __name__ == '__main__':
10    result = []
11    for name in ('alex', 'test', 'bob'):
12        q = Queue()
13        p = Process(target=f, args=(name, q))
14        p.start()
15        p.join()
16        for _ in range(q.qsize()):
17            result.append(q.get())
18    print(result)

Этот код выведет:

[
('hello_0', 'alex'), ('hello_1', 'alex'), ('hello_2', 'alex'), 
('hello_0', 'test'), ('hello_1', 'test'), ('hello_2', 'test'), 
('hello_0', 'bob'), ('hello_1', 'bob'), ('hello_2', 'bob')
]

Хорошо, но теперь есть желание посмотреть как сильно использование multiprocessing может ускорить какую-либо задачу, хотя бы конкретно на моей машине. Я решил сделать такой тест, используя модуль timeit, так:

 1from multiprocessing import Process, Queue
 2import timeit
 3
 4
 5def f(name, q):
 6    for i in range(1000):
 7        q.put(('hello_{0}'.format(i), name))
 8
 9
10def multiprocessing_test(names):
11    """Тест функции cо многими процессами."""
12    result = []
13    for name in names:
14        q = Queue()
15        p = Process(target=f, args=(name, q))
16        p.start()
17        p.join()
18        for _ in range(q.qsize()):
19            result.append(q.get())
20
21
22def without_multi_test(names):
23    """Тест обычной функции."""
24    result = []
25    for name in names:
26        q = Queue()
27        f(name, q)
28        for _ in range(q.qsize()):
29            result.append(q.get())
30
31
32if __name__ == '__main__':
33    names = ('alex', 'test', 'bob', 'lol1', 'lol2', 'lol3')
34    print(timeit.timeit(lambda: multiprocessing_test(names), number=10))
35    print(timeit.timeit(lambda: without_multi_test(names), number=10))

Получилось, что для этой задачи, на таких объемах данных, применение multiprocessing оправдано:

1.7380545689957216
2.3318959810130764

Интересно, что если я снижал количество итераций в функции f до 100, то обычный код начинал работать быстрее, вообще, получилось интересно.

Метки

python
Если вам понравился пост, можете поделиться им в соцсетях: