Многопроцессорность в Python на примерах
В этом руководстве вы узнаете, как параллельно запускать код с помощью модуля multiprocessing в Python.
- Что такое многопроцессорность в Python?
- Пример многопроцессорности Python
- Использование модуля multiprocessing
- Практический пример многопроцессорной обработки в Python
Что такое многопроцессорность в Python?
Обычно программы решают два типа задач:
- Задачи, связанные с вводом-выводом: такая задача выполняет множество операций ввода-вывода. Типичными примерами задач, связанных с вводом-выводом, являются чтение из файлов, запись в файлы, подключение к базам данных и выполнение сетевого запроса. Для задач, связанных с вводом-выводом, вы можете использовать многопоточность для их ускорения.
- Задачи с привязкой к ЦП: такая задача выполняет много операций с использованием ЦП. Например, вычисление чисел, изменение размера изображения и потоковое видео — это задачи, связанные с процессором. Чтобы ускорить работу программы с большим количеством задач, связанных с процессором, используйте многопроцессорность.
Многопроцессорность позволяет двум или более процессорам одновременно обрабатывать две или более различных частей программы. В Python для реализации многопроцессорности используется модуль multiprocessing.
Пример многопроцессорности Python
Смотрите следующую программу:
import time def task(): result = 0 for _ in range(10**8): result += 1 return result if __name__ == '__main__': start = time.perf_counter() task() task() finish = time.perf_counter() print(f'It took {finish-start:.2f} second(s) to finish')
Выход:
It took 5.55 second(s) to finish
Как это работает.
- Во-первых, определите, что функция Task() является задачей, привязанной к ЦП, поскольку она выполняет тяжелые вычисления, выполняя цикл на 100 миллионов итераций и увеличивая результат переменной:
def task(): result = 0 for _ in range(10**8): result += 1 return result
- Во-вторых, дважды вызовите функции Task() и запишите время обработки:
if __name__ == '__main__': start = time.perf_counter() task() task() finish = time.perf_counter() print(f'It took {finish-start: .2f} second(s) to finish')
На нашем компьютере это заняло 5,55 секунды.
Использование модуля multiprocessing
Следующая программа использует модуль multiprocessing, но занимает меньше времени:
import time import multiprocessing def task() -> int: result = 0 for _ in range(10**8): result += 1 return result if __name__ == '__main__': start = time.perf_counter() p1 = multiprocessing.Process(target=task) p2 = multiprocessing.Process(target=task) p1.start() p2.start() p1.join() p2.join() finish = time.perf_counter() print(f'It took {finish-start:.2f} second(s) to finish')
Выход:
It took 3.43 second(s) to finish
Как это работает.
- Сначала импортируйте модуль multiprocessing:
import multiprocessing
- Во-вторых, создайте два процесса и передайте каждому функцию задачи:
p1 = multiprocessing.Process(target=task) p2 = multiprocessing.Process(target=task)
Обратите внимание, что конструктор Process() возвращает новый объект Process.
- В-третьих, вызовите метод start() объектов Process, чтобы запустить процесс:
p1.start() p2.start()
- Наконец, дождитесь завершения процессов, вызвав метод join():
p1.join() p2.join()
Практический пример многопроцессорной обработки в Python
Мы будем использовать модуль multiprocessing для изменения размера изображений с высоким разрешением.
- Сначала установите библиотеку Pillow для обработки изображений:
pip install Pillow
- Во-вторых, разработайте программу, которая создает миниатюры изображений в папке изображений и сохраняет их в папке миниатюр:
import time import os from PIL import Image, ImageFilter filenames = [ 'images/1.jpg', 'images/2.jpg', 'images/3.jpg', 'images/4.jpg', 'images/5.jpg', ] def create_thumbnail(filename, size=(50,50), thumb_dir ='thumbs'): # open the image img = Image.open(filename) # apply the gaussian blur filter img = img.filter(ImageFilter.GaussianBlur()) # create a thumbnail img.thumbnail(size) # save the image img.save(f'{thumb_dir}/{os.path.basename(filename)}') # display a message print(f'{filename} was processed...') if __name__ == '__main__': start = time.perf_counter() for filename in filenames: create_thumbnail(filename) finish = time.perf_counter() print(f'It took {finish-start:.2f} second(s) to finish')
На нашем компьютере это заняло около 4,06 секунды:
images/1.jpg was processed... images/2.jpg was processed... images/3.jpg was processed... images/4.jpg was processed... images/5.jpg was processed... It took 4.06 second(s) to finish
- В-третьих, измените программу, чтобы она использовала многопроцессорность. Каждый процесс создаст миниатюру для изображения:
import time import os from PIL import Image, ImageFilter import multiprocessing filenames = [ 'images/1.jpg', 'images/2.jpg', 'images/3.jpg', 'images/4.jpg', 'images/5.jpg', ] def create_thumbnail(filename, size=(50,50), thumb_dir ='thumbs'): # open the image img = Image.open(filename) # apply the gaussian blur filter img = img.filter(ImageFilter.GaussianBlur()) # create a thumbnail img.thumbnail(size) # save the image img.save(f'{thumb_dir}/{os.path.basename(filename)}') # display a message print(f'{filename} was processed...') def main(): start = time.perf_counter() # create processes processes = [multiprocessing.Process(target=create_thumbnail, args=[filename]) for filename in filenames] # start the processes for process in processes: process.start() # wait for completion for process in processes: process.join() finish = time.perf_counter() print(f'It took {finish-start:.2f} second(s) to finish') if __name__ == '__main__': main()
Выход:
images/5.jpg was processed... images/4.jpg was processed... images/1.jpg was processed... images/3.jpg was processed... images/2.jpg was processed... It took 2.92 second(s) to finish
В этом случае вывод показывает, что программа обработала снимки быстрее.