Multiprocessing Python
Введение | |
Пример | |
Цикл | |
Более сложный пример | |
Похожие статьи |
Введение
В этой статье вы узнаете как запускать несколько процессов одновременно.
Простой пример
Рассмотрим функцию do_something()
def do_something(): print('Sleeping 1 second...') time.sleep(1) print('Done Sleeping...')
Допустим, нужно выполнить её два раза подряд. Сколько на это уйдёт времени?
Зависит от того как вызывать функцию. Если последовательно, то около двух секунд. Проверим.
import time def main(): start = time.perf_counter() do_something() do_something() finish = time.perf_counter() print(f'Finished in {round(finish-start, 2)} second(s)') def do_something(): print('Sleeping 1 second...') time.sleep(1) print('Done Sleeping...') if __name__ == "__main__": main()
python conseq.py
Sleeping 1 second... Done Sleeping... Sleeping 1 second... Done Sleeping... Finished in 2.0 second(s)
Действительно, ушло две секунды. Сократить это время поможет multiprocessing
import multiprocessing import time def main(): start = time.perf_counter() p1 = multiprocessing.Process(target=do_something) p2 = multiprocessing.Process(target=do_something) p1.start() p2.start() p1.join() p2.join() finish = time.perf_counter() print(f'Finished in {round(finish-start, 2)} second(s)') def do_something(): print('Sleeping 1 second...') time.sleep(1) print('Done Sleeping...') if __name__ == "__main__": main()
python multip.py
Sleeping 1 second... Sleeping 1 second... Done Sleeping... Done Sleeping... Finished in 1.01 second(s)
Потребовалось всего 1.01 секунда
Цикл
Когда нужно запустить большое количество процессов одновременно, это
можно сделать с помощью цикла.
В таргет можно передавать аргументы. Изменим функцию do_something()
чтобы она принимала время и текст
import multiprocessing import time def main(): NUMBER_OF_TASKS = 10 p_list = [] start = time.perf_counter() for _ in range(0, NUMBER_OF_TASKS): sleep = 1 action = "Relaxing" p = multiprocessing.Process(target=do_something, args=(sleep, action)) p.start() p_list.append(p) for process_ in p_list: process_.join() finish = time.perf_counter() print(f'Finished in {round(finish-start, 2)} second(s)') def do_something(sleep: int, action: str) -> None: print(f'{action} {sleep} second...') time.sleep(sleep) print('Done Sleeping...')
python multip.py
Relaxing 1 second... Relaxing 1 second... Relaxing 1 second... Relaxing 1 second... Relaxing 1 second... Relaxing 1 second... Relaxing 1 second... Relaxing 1 second... Relaxing 1 second... Relaxing 1 second... Done Sleeping... Done Sleeping... Done Sleeping... Done Sleeping... Done Sleeping... Done Sleeping... Done Sleeping... Done Sleeping... Done Sleeping... Done Sleeping... Finished in 1.01 second(s)
На десять вызовов подряд потребовалось бы 10 секунд, а с multiprocessing по-прежнему хватает одной с небольшим.
Приближенный к жизни пример
import requests import multiprocessing import datetime import sys import urllib3 import time import subprocess urllib3.disable_warnings(urllib3.exceptions.InsecureRequestWarning) NUMBER_OF_TASKS = int(sys.argv[1]) p_list = [] def main(): main_start_time = datetime.datetime.utcnow() for _ in range(0, NUMBER_OF_TASKS): p = multiprocessing.Process(target=connect_to_url) p.start() p_list.append(p) for process_ in p_list: process_.join() main_finish_time = datetime.datetime.utcnow() tdelta = main_finish_time - main_start_time finish = time.perf_counter() with open("performance_data.txt", "a") as pf: pf.write( f"Started: {main_start_time}; " f"Nprocesses: {NUMBER_OF_TASKS }; " f"Elapsed time: {tdelta}; " f"Nerrors: {ERR_COUNT} \r\n" ) def connect_to_url(): url = 'https://192.168.0.2/authentication/api/oauth2/token' auth = ('secret_name','secret_code') payload = { 'grant_type': 'password', 'username': 'secret_username', 'password': 'secret_password', } r = requests.post(url, auth=auth, data=payload, verify=False) _status_code = r.status_code if _status_code != 200: print(_status_code) err_log_name = main_start_time + "_error_log.txt" with open("./logs/{err_log_name}", "a") as pf: pf.write(f"Error: {_status_code} \r\n") if __name__ == '__main__': main()