Многозадачность стала проще благодаря примерам Python

Многопоточность и многопроцессорность — два способа достижения многозадачности (подумайте о распределенных вычислениях!) в Python. Многозадачность полезна при параллельном выполнении функций и кода, например при разбиении математических вычислений на несколько более мелких частей или разделении элементов в цикле for, если они независимы друг от друга. другой. В этой статье будут представлены и сравнены различия между многопоточностью и многопроцессорностью, когда использовать каждый метод и как их реализовать в Python.

Обновление: эта статья является частью серии. Ознакомьтесь с другими темами за 10 минут здесь!

Оглавление

  1. Многопоточность против многопроцессорности
  2. Многопоточность как функция Python
  3. Многопоточность как класс Python
  4. Многопроцессорность как функция Python

Многопоточность против многопроцессорности

По формальному определению многопоточность относится к способности процессора одновременно выполнять несколько потоков, при этом каждый поток запускает процесс. Принимая во внимание, что многопроцессорностьотносится к способности системы одновременно запускать несколько процессоров, где каждый процессор может запускать один или несколько потоков.

Из приведенной выше диаграммы видно, что при многопоточности (средняя диаграмма) несколько потоков совместно используют один и тот же код, данные и файлы, но работают в разных регистрах и стеках. Многопроцессорность (правая диаграмма) умножает один процессор — реплицируя код, данные и файлы, что влечет за собой дополнительные накладные расходы.

Многопоточность полезна для процессов, связанных с вводом-выводом, таких как чтение файлов из сети или базы данных, поскольку каждый поток может одновременно выполнять процесс, связанный с вводом-выводом. Многопроцессорность полезна для процессов, привязанных к ЦП, таких как задачи, требующие больших вычислительных ресурсов, поскольку она выигрывает от наличия нескольких процессоров; подобно тому, как многоядерные компьютеры работают быстрее, чем компьютеры с одним ядром.

Обратите внимание, что использование многопоточности для процессов, привязанных к ЦП, может снизить производительность из-за конкурирующих ресурсов, которые гарантируют, что только один поток может выполняться одновременно, и возникают накладные расходы при работе с несколькими потоками.

С другой стороны, многопроцессорность может использоваться для процессов, связанных с вводом-выводом. Однако накладные расходы на управление несколькими процессами выше, чем на управление несколькими потоками, как показано выше. Вы можете заметить, что многопроцессорность может привести к более высокой загрузке ЦП из-за того, что программа использует несколько ядер ЦП, что и ожидается.

Многопоточность как функция Python

Многопоточность может быть реализована с помощью встроенной библиотеки Python threading и выполняется в следующем порядке:

  1. Создать поток: каждый поток должен быть помечен функцией Python с ее аргументами.
  2. Начать выполнение задачи
  3. Подождите, пока поток завершит выполнение: полезно для обеспечения завершения или «контрольных точек».

В приведенном ниже фрагменте кода реализованы описанные выше шаги вместе с блокировкой потока (строка 22) для обработки конкурирующих ресурсов, что в нашем случае необязательно.

Есть несколько примечательных наблюдений

  • Строка 12–15: процессы выполняются в разных потоках (идентификатор потока), но с одним и тем же процессором (идентификатор процесса).
  • Строка 8: Если бы вместо этого было реализовано time.sleep(sleep_duration) между получением и освобождением блокировки, потоки будут выполняться последовательно, и не будет никакой экономии времени — вы можете попробовать!

Многопоточность как класс Python

Для пользователей, предпочитающих объектно-ориентированное программирование, многопоточность может быть реализована в виде класса Python, наследуемого от суперкласса threading.Thread. Одним из преимуществ использования классов вместо функций будет возможность совместного использования переменных через объекты класса.

Разница между реализацией многопоточности как функции и класса будет заключаться в шаге 1 (создание потока), поскольку теперь поток помечается методом класса, а не функцией. Последующие шаги для вызова t1.start() и t1.join() остаются прежними.

import time

class Sleep(threading.Thread):
    def __init__(self, sleep_duration):
        self.sleep_duration = sleep_duration

    def sleep(self):
        time.sleep(self.sleep_duration)

if __name__ == "__main__":
    # Create thread
    sleep_class = Sleep(2)
    t1 = threading.Thread(target=sleep_class.sleep)

Многопроцессорность как функция Python

Многопроцессорность может быть реализована с помощью встроенной библиотеки Python multiprocessing с использованием двух разных методов — Process и Pool.

Метод Process подобен описанному выше многопоточному методу, в котором каждый процесс помечается функцией со своими аргументами. В приведенном ниже фрагменте кода мы видим, что многопроцессорная обработка занимает больше времени, чем многопоточность, поскольку при работе с несколькими процессорами больше накладных расходов.

Пулметод позволяет пользователям определять количество рабочих процессов и распределять все процессы по доступным процессорам по расписанию «первым поступил — первым обслужен», автоматически обрабатывая планирование процессов. Метод пула используется для разбиения функции на несколько небольших частей с использованием map или starmap (строка 19) — запуск одной и той же функции с разными входными аргументами. В то время как метод Process используется для запуска различных функций.

Надеюсь, что эта статья представила концепцию многопоточности и многопроцессорности, а также когда использовать каждый метод. Примеры Python — это скелетные фрагменты кода, которые вы можете заменить своими функциями, и все готово!

Спасибо за прочтение! Если вам понравилась эта статья, поделитесь ею.

Ссылки по теме

threading Документация по Python: https://docs.python.org/3/library/threading.html

multiprocessing Документация по Python: https://docs.python.org/3/library/multiprocessing.html