Фон
Python предлагает несколько подходов к параллелизму и параллелизму.
Двумя наиболее популярными способами параллельного выполнения в Python являются многопоточность и многопроцессорность. Хотя оба метода направлены на повышение производительности программы Python, они различаются по своему подходу и вариантам использования.
В этом сегменте я расскажу, когда следует использовать многопоточность и/или многопроцессорность в Python для достижения хороших и производительных результатов кода.
Многопоточность
Многопоточность — это метод, при котором один процесс или программа делится на несколько потоков выполнения.
Каждый поток выполняется одновременно, используя одно и то же пространство памяти и системные ресурсы. В Python многопоточность реализуется с помощью модуля threading.
Основное преимущество многопоточности заключается в том, что она обеспечивает параллелизм без накладных расходов на создание новых процессов. Это делает его подходящим для задач, связанных с вводом-выводом, таких как сетевые запросы, файловый ввод-вывод и операции с базой данных, где узким местом обычно является время, затрачиваемое на ожидание внешних ресурсов. Используя потоки, мы можем одновременно выполнять несколько задач, связанных с вводом-выводом, что может значительно повысить общую производительность программы.
Однако многопоточность может не подходить для задач, связанных с ЦП, таких как математические вычисления, обработка изображений и рендеринг видео, где узким местом является время ЦП. Это связано с тем, что Python использует глобальную блокировку интерпретатора (GIL), которая предотвращает одновременное выполнение байт-кода Python несколькими потоками.
Хотя несколько потоков могут выполняться одновременно, они не могут параллельно выполнять задачи, связанные с ЦП. Поэтому в таких случаях многопроцессорность является лучшим выбором.
Вот пример многопоточности в Python:
import threading def print_numbers(): for i in range(10): print(i) def print_letters(): for letter in 'abcdefghij': print(letter) thread1 = threading.Thread(target=print_numbers) thread2 = threading.Thread(target=print_letters) thread1.start() thread2.start() thread1.join() thread2.join() print("Done")
В этом примере у нас есть две функции: print_numbers() и print_letters(), каждая из которых выполняется в отдельном потоке.
Класс Thread из модуля threading используется для создания двух потоков, каждый из которых предназначен для одной из двух функций. Метод start() вызывается в каждом потоке, чтобы начать выполнение, а метод join() вызывается в каждом потоке, чтобы дождаться их завершения. Наконец, программа печатает «Готово», чтобы указать, что оба потока завершили выполнение.
Многопроцессорность
Многопроцессорность — это метод, при котором программа или процесс делится на несколько независимых процессов, каждый из которых выполняется в отдельной области памяти.
Каждый процесс имеет собственный интерпретатор и виртуальную машину Python (PVM) и может выполнять код Python параллельно на разных ядрах ЦП. В Python многопроцессорность реализуется с помощью модуля multiprocessing.
Основное преимущество многопроцессорной обработки заключается в том, что она обеспечивает настоящий параллелизм для задач, связанных с ЦП. Используя несколько процессов, мы можем распределить рабочую нагрузку между несколькими ядрами ЦП, что может значительно сократить время выполнения задач, связанных с ЦП. Однако многопроцессорность сопряжена с некоторыми накладными расходами, поскольку каждый процесс должен быть создан и инициализирован, а связь между процессами может быть медленнее, чем связь между потоками.
Многопроцессорность подходит для задач, связанных с ЦП, где узким местом является время ЦП. Это также полезно, когда нам нужно изолировать процесс от основной программы, например, при запуске ненадежной сторонней библиотеки, которая может привести к сбою или повреждению памяти основной программы.
Вот пример многопроцессорности в Python:
import multiprocessing def square(number): return number * number if __name__ == '__main__': numbers = [1, 2, 3, 4, 5] pool = multiprocessing.Pool(processes=3)
Краткое содержание
Подводя итог, можно сказать, что выбор между использованием многопроцессорности и многопоточности в Python зависит от характера решаемой задачи.
Многопоточность подходит для задач, связанных с вводом-выводом, где узким местом обычно является время, затрачиваемое на ожидание внешних ресурсов, таких как сетевые запросы, файловый ввод-вывод и операции с базой данных. Это связано с тем, что многопоточность обеспечивает параллелизм без накладных расходов на создание новых процессов.
С другой стороны, многопроцессорность подходит для задач, связанных с ЦП, где узким местом является время ЦП, например математические вычисления, обработка изображений и рендеринг видео. Это связано с тем, что многопроцессорность обеспечивает настоящий параллелизм, распределяя рабочую нагрузку между несколькими ядрами ЦП.
Кроме того, важно отметить, что глобальная блокировка интерпретатора Python (GIL) предотвращает одновременное выполнение байт-кода Python несколькими потоками. В результате многопоточность может не подходить для задач, связанных с ЦП, которые требуют параллелизма, и в таких случаях предпочтительнее использовать многопроцессорность.