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

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

Пробую multiprocessing в Python 3

8 мая 2020 г.

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

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

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

Запустим:

hello bob

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

 1 from multiprocessing import Process
 2 
 3 
 4 def f(name):
 5     print('hello', name)
 6 
 7 
 8 if __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, примерно так:

 1 from multiprocessing import Process, Queue
 2 
 3 
 4 def f(name, q):
 5     for i in range(3):
 6         q.put(('hello_{0}'.format(i), name))
 7 
 8 
 9 if __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, так:

 1 from multiprocessing import Process, Queue
 2 import timeit
 3 
 4 
 5 def f(name, q):
 6     for i in range(1000):
 7         q.put(('hello_{0}'.format(i), name))
 8 
 9 
10 def 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 
22 def 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 
32 if __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
Если вам понравился пост, можете поделиться им в соцсетях: