Часть II Практическое кодирование
После понимания разницы между многопоточностью и многопроцессорностью, если вы не уверены в том, что это за две концепции, ознакомьтесь с предыдущей статьей: Многопоточность и многопроцессорность в Python
Часть I Говоря в теории, и теперь мы собираемся реализовать это с помощью кода Python!
Многопоточность
Реализация и интерпретация
Во всех примерах мы сосредоточимся на функции с именем go_sleep().
Обычно, когда мы запускаем функцию несколько раз, она сначала выполняет первую, затем выполняет вторую после завершения и так далее.
В этом случае мы запускаем go_sleep() пять раз и записываем время начала и окончания, чтобы увидеть, сколько времени затрачено. Как вы можете видеть в выходных данных, он печатает Sleep 1 sec (s), затем Done sleep для первого выполнения, за которым следует второе выполнение до последнего, они выполняются чтобы. Всего потрачено 5,01 секунды.
import time
start = time.perf_counter()
def go_sleep(sec):
print('Sleep {} sec(s)'.format(sec))
time.sleep(sec)
print('Done sleep')
for _ in range(5):
go_sleep(1)
finish = time.perf_counter()
print('Finished in {} second(s)'.format(round(finish-start, 2)))
>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
Sleep 1 sec(s)
Done sleep
Sleep 1 sec(s)
Done sleep
Sleep 1 sec(s)
Done sleep
Sleep 1 sec(s)
Done sleep
Sleep 1 sec(s)
Done sleep
Finished in 5.03 second(s)
Теперь посмотрим, что, если мы воспользуемся многопоточностью для выполнения функции пять раз.
импорт цепочки
Мы вызываем threading module и указываем go_sleep() в качестве цели, args равняется одной секунде, как указано выше. используйте start(), чтобы начать поток, и используйте join(), чтобы поймать конец потока. Таким образом, потоки выполняются один за другим, не дожидаясь завершения предыдущего, видите, общее время завершения составляет 1,03 секунды, огромное сокращение, верно!
import time
import threading
start = time.perf_counter()
def go_sleep(sec):
print('Sleep {} sec(s)'.format(sec))
time.sleep(sec)
print('Done sleep')
threads = []
for _ in range(5):
t = threading.Thread(target=go_sleep, args=[1])
t.start()
threads.append(t)
for thread in threads:
thread.join()
finish = time.perf_counter()
print('Finished in {} second(s)'.format(round(finish-start, 2)))
>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
Sleep 1 sec(s)
Sleep 1 sec(s)
Sleep 1 sec(s)
Sleep 1 sec(s)
Sleep 1 sec(s)
Done sleepDone sleep
Done sleepDone sleep
Done sleep
Finished in 1.03 second(s)
Примечание: не забудьте вызвать thread.join() после запуска потока, это гарантирует, что поток завершен, а затем непрерывно выполнит следующий код, в противном случае он выполнит следующий код независимо от того, закончен протектор или нет, в этом примере, если вы вводите команду for loop thead.join(), в результате перед сном Done будет напечатано сообщение Finished. Вы определенно можете попробовать это сами с помощью файла ipynb , который я привожу в конце этой статьи, чтобы увидеть разницу!
импортировать concurrent.futures
это еще один модуль, который может реализовать многопоточность, поскольку он требует возвращаемого значения, мы меняем последний код нашей функции с printin на return.
Отправьте исполнителя, чтобы он запустился и получил возвращаемое значение типа списка, используя функцию as_completed(), которая сможет получить результаты в соответствии с порядком, в котором они завершили выполнение.
Как и в этом примере, хотя он впервые выполняет go_sleep() с 5 секунд в качестве аргумента, самое быстрое отображение в as_completed() - это 1 секунда в качестве аргумента, затем последний - 5 секунд. потому что ему нужно поспать 5 секунд, что вполне логично, правда?
import time
import concurrent.futures
start = time.perf_counter()
def go_sleep(sec):
print('Sleep {} sec(s)'.format(sec))
time.sleep(sec)
return 'Done sleep {}'.format(sec)
with concurrent.futures.ThreadPoolExecutor() as executor:
secs = [5, 4, 3, 2, 1]
results = [executor.submit(go_sleep, sec) for sec in secs]
for f in concurrent.futures.as_completed(results):
print(f.result())
finish = time.perf_counter()
print('Finished in {} second(s)'.format(round(finish-start, 2)))
>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
Sleep 5 sec(s)
Sleep 4 sec(s)
Sleep 3 sec(s)
Sleep 2 sec(s)
Sleep 1 sec(s)
Done sleep 1
Done sleep 2
Done sleep 3
Done sleep 4
Done sleep 5
Finished in 5.02 second(s)
с помощью executeor.map ()
Что, если мы хотим выполнить и распечатать результат в том же порядке? Нет проблем! Вместо этого используется executor.map(). В этом примере он выполняет функцию в порядке [5, 4, 3, 2, 1], как вы можете себе представить, 1-секундный завершился первым, но его результат не распечатался как первый, он просто печатает Done Sleep 5 и т. д. по порядку! Что делать, если вам не нужна распечатка сообщения с результатами? Конечно! Просто закомментируйте for loop print result часть, легко!
import time
import concurrent.futures
start = time.perf_counter()
def go_sleep(sec):
print('Sleep {} sec(s)'.format(sec))
time.sleep(sec)
return 'Done sleep {}'.format(sec)
with concurrent.futures.ThreadPoolExecutor() as executor:
secs = [5, 4, 3, 2, 1]
results = executor.map(go_sleep, secs)
for result in results:
print(result)
finish = time.perf_counter()
print('Finished in {} second(s)'.format(round(finish-start, 2)))
>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
Sleep 5 sec(s)
Sleep 4 sec(s)
Sleep 3 sec(s)
Sleep 2 sec(s)
Sleep 1 sec(s)
Done sleep 5
Done sleep 4
Done sleep 3
Done sleep 2
Done sleep 1
Finished in 5.01 second(s)
Многопроцессорность
Реализация и интерпретация
Как только вы поймете, как использовать сценарии для реализации многопоточности, способ реализации многопроцессорности будет почти таким же!
Обратите внимание: насколько ускорение программы за счет многопроцессорной обработки зависит от того, сколько ядер у вашего компьютера. Вы должны знать, что если ваш компьютер имеет только три ядра, даже если вы запустите 5 обработок, в одном и том же процессе будут выполняться только три процесса. Четвертый и пятый процесс будут ждать, пока одно из трех ядер завершит свою текущую задачу, а затем быть исполненным.
импорт многопроцессорности
import time
import multiprocessing
start = time.perf_counter()
def go_sleep(sec):
print('Sleep {} sec(s)'.format(sec))
time.sleep(sec)
print('Done sleep')
processes = []
for _ in range(5):
p = multiprocessing.Process(target=go_sleep, args=[1])
p.start()
processes.append(p)
for process in processes:
process.join()
finish = time.perf_counter()
print('Finished in {} second(s)'.format(round(finish-start, 2)))
импортировать concurrent.futures
Да ты прав. Это тот же самый модуль, который мы только что использовали в многопоточности. Но мы вызываем функцию ProcessPoolExecutor вместо ThreadPoolExecutor.
import time
import concurrent.futures
start = time.perf_counter()
def go_sleep(sec):
print('Sleep {} sec(s)'.format(sec))
time.sleep(sec)
return 'Done sleep {}'.format(sec)
with concurrent.futures.ProcessPoolExecutor() as executor:
secs = [5, 4, 3, 2, 1]
results = [executor.submit(go_sleep, sec) for sec in secs]
#for f in concurrent.futures.as_completed(results):
# print(f.result())
finish = time.perf_counter()
print('Finished in {} second(s)'.format(round(finish-start, 2)))
вы также можете использовать executor.map()
import time
import concurrent.futures
start = time.perf_counter()
def go_sleep(sec):
print('Sleep {} sec(s)'.format(sec))
time.sleep(sec)
return 'Done sleep {}'.format(sec)
with concurrent.futures.ProcessPoolExecutor() as executor:
secs = [5, 4, 3, 2, 1]
results = executor.map(go_sleep, secs)
#for result in results:
# print(result)
finish = time.perf_counter()
print('Finished in {} second(s)'.format(round(finish-start, 2)))
Примечание. Если вы столкнулись с такой ошибкой: concurrent.futures.process.BrokenProcessPool: процесс в пуле процессов был внезапно завершен во время выполнения будущего или ожидания.
Вероятно, потому, что у вас недостаточно памяти для обработки.
Надеюсь, вам понравится! Завершите свою программу в невероятные сроки!
Я загрузил эти два кода концепций на свой Github. Всем, кто хочет попробовать, как это работает, не стесняйтесь посетить и загрузить ресурс.
https://github.com/alliehsu05/Python-MultithreadingandMultiprocessing
использованная литература
- Учебное пособие по многопроцессорной обработке Python: параллельное выполнение кода с помощью модуля многопроцессорности
- Учебное пособие по потоковой передаче Python: одновременное выполнение кода с помощью модуля потоковой передачи
- Https://blog.gtwang.org/programming/python-threading-multithreaded-programming-tutorial/