Sobes.tech
Middle
174

Care este diferența dintre programarea asincronă, fire de execuție și procesarea multiprocesor?

Răspuns de la AI

sobes.tech AI

Аспект Асинхронное программирование Потоки (Threads) Мультипроцессорная обработка (Multiprocessing)
Параллелизм Псевдо-параллелизм (Concurrent) на одном ядре Псевдо-параллелизм (Concurrent) на одном ядре Истинный параллелизм (Parallel) на разных ядрах
Реализация Однопоточная, управляемое циклом событий (event loop) Потоки внутри одного процесса Отдельные процессы
Обмен данными Общие переменные с осторожностью (единый процесс) Общие переменные, блокировки (GIL в Python) Каналы, очереди, общая память (менее тривиально из-за отдельных адресных пространств)
Переключение контекста Быстрое, на уровне корутин/функций Быстрое, на уровне ядра ОС Медленнее, на уровне процессов ОС
Использование CPU Простаивает во время ожидания ввода/вывода Блокируется во время ожидания ввода/вывода Полностью использует доступные ядра CPU
Лучшие сценарии Ввод/вывод-связанные задачи (сеть, файлы) Задачи, где блокируется только один поток (хоть и с GIL) Вычислительно-интенсивные задачи
Пример Ожидание ответа от сервера Фоновое сохранение файла Параллельная обработка больших данных

Асинхронное программирование в Python основано на asyncio и позволяет управлять множеством операций ввода/вывода эффективно в одном потоке. Вместо того чтобы блокироваться, функция "приостанавливается" и передает управление циклу событий, который может выполнять другие задачи, пока операция не завершится.

Потоки работают внутри одного процесса и делят общее адресное пространство памяти. Однако в CPython существует Global Interpreter Lock (GIL), который фактически не позволяет нескольким потокам выполнять код на Python одновременно на разных ядрах CPU. Поэтому потоки более полезны для задач, связанных с вводом/выводом, где освобождается GIL во время ожидания. Для CPU-bound задач GIL становится бутылочным горлышком.

Мультипроцессорная обработка запускает независимые процессы с собственными адресными пространствами памяти. Каждый процесс имеет свой собственный интерпретатор Python и GIL. Это позволяет достичь истинного параллелизма, распределяя вычислительно-интенсивные задачи между доступными ядрами CPU. Обмен данными между процессами требует явных механизмов, таких как очереди или каналы, поскольку они не делят память напрямую.

# Пример асинхронного кода
import asyncio

async def task1():
    print("Начало задачи 1")
    await asyncio.sleep(1) // Имитация асинхронной операции
    print("Конец задачи 1")

async def task2():
    print("Начало задачи 2")
    await asyncio.sleep(2) // Имитация асинхронной операции
    print("Конец задачи 2")

async def main():
    await asyncio.gather(task1(), task2())

// Запуск асинхронного цикла событий
if __name__ == "__main__":
    asyncio.run(main())
# Пример использования потоков
import threading
import time

def task1():
    print("Начало потока 1")
    time.sleep(1) // Может блокировать основной поток (с точки зрения GIL)
    print("Конец потока 1")

def task2():
    print("Начало потока 2")
    time.sleep(2) // Может блокировать основной поток (с точки зрения GIL)
    print("Конец потока 2")

// Создание и запуск потоков
thread1 = threading.Thread(target=task1)
thread2 = threading.Thread(target=task2)

thread1.start()
thread2.start()

// Ожидание завершения потоков
thread1.join()
thread2.join()

print("Все потоки завершены")
# Пример использования мультипроцессорной обработки
import multiprocessing
import time

def task1():
    print(f"Начало процесса 1 (PID: {multiprocessing.current_process().pid})")
    time.sleep(1) // Работает независимо от других процессов
    print(f"Конец процесса 1 (PID: {multiprocessing.current_process().pid})")

def task2():
    print(f"Начало процесса 2 (PID: {multiprocessing.current_process().pid})")
    time.sleep(2) // Работает независимо от других процессов
    print(f"Конец процесса 2 (PID: {multiprocessing.current_process().pid})")

// Создание и запуск процессов
if __name__ == "__main__":
    process1 = multiprocessing.Process(target=task1)
    process2 = multiprocessing.Process(target=task2)

    process1.start()
    process2.start()

    // Ожидание завершения процессов
    process1.join()
    process2.join()

    print("Все процессы завершены")