Многопроцессорность в Python на примерах

В этом руководстве вы узнаете, как параллельно запускать код с помощью модуля multiprocessing в Python.

Содержание

Что такое многопроцессорность в Python?

Обычно программы решают два типа задач:

  1. Задачи, связанные с вводом-выводом: такая задача выполняет множество операций ввода-вывода. Типичными примерами задач, связанных с вводом-выводом, являются чтение из файлов, запись в файлы, подключение к базам данных и выполнение сетевого запроса. Для задач, связанных с вводом-выводом, вы можете использовать многопоточность для их ускорения.
  2. Задачи с привязкой к ЦП: такая задача выполняет много операций с использованием ЦП. Например, вычисление чисел, изменение размера изображения и потоковое видео — это задачи, связанные с процессором. Чтобы ускорить работу программы с большим количеством задач, связанных с процессором, используйте многопроцессорность.

Многопроцессорность позволяет двум или более процессорам одновременно обрабатывать две или более различных частей программы. В 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

В этом случае вывод показывает, что программа обработала снимки быстрее.

Похожие посты
Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *