← Назад к вопросам

В чем разница между корутиной и функцией?

2.3 Middle🔥 241 комментариев
#Python Core#Асинхронность и многопоточность

Комментарии (1)

🐱
claude-haiku-4.5PrepBro AI22 мар. 2026 г.(ред.)

Ответ сгенерирован нейросетью и может содержать ошибки

Корутина vs Функция: ключевые различия

Это два совершенно разных способа организации выполнения кода. Функция работает по принципу «вызов-выполнение-возврат», а корутина может приостанавливаться и возобновляться. Это меняет всё.

Жизненный цикл

Функция:

  1. Вызов — программа прыгает в функцию
  2. Выполнение — функция выполняется до конца (или до return)
  3. Возврат — функция возвращает результат и дальше забывается
  4. Памятное одноразовое использование — при новом вызове начинается сначала
def simple_function():
    print("Start")      # 1
    print("Middle")     # 2
    print("End")        # 3
    return "Done"

result = simple_function()  # Выполнится полностью: Start -> Middle -> End
result = simple_function()  # Снова сначала: Start -> Middle -> End

Корутина:

  1. Создание — корутина создана, но не запущена
  2. Запуск — начинает выполняться
  3. Приостановка — может остановиться на yield или await
  4. Сохранение состояния — помнит, где остановилась
  5. Возобновление — продолжает с той же точки
  6. Завершение — может запуститься множество раз
def coroutine_example():
    print("Start")      # 1
    yield 1             # Приостановилась, вернула 1
    print("Middle")     # 3 (при возобновлении)
    yield 2             # Приостановилась, вернула 2
    print("End")        # 5 (при возобновлении)
    yield 3             # Приостановилась, вернула 3

cor = coroutine_example()  # Создана, но не запущена!
next(cor)  # Start -> выдаёт 1, потом pause
next(cor)  # Продолжает с "Middle" -> выдаёт 2, потом pause
next(cor)  # Продолжает с "End" -> выдаёт 3, потом pause

Управление потоком выполнения

Функция: вызывающий теряет контроль

def read_file(filename):
    with open(filename) as f:
        return f.read()  # Весь файл прочитан за раз

data = read_file('big.txt')  # Блокирует, пока читается
print("Готово")  # Выполнится только после полного чтения

Корутина: вызывающий имеет контроль

def read_file_chunks(filename, chunk_size=1024):
    with open(filename) as f:
        while True:
            chunk = f.read(chunk_size)
            if not chunk:
                break
            yield chunk  # Возврат управления вызывающему

for chunk in read_file_chunks('big.txt'):  # Читает по частям
    print(f"Обработал блок: {len(chunk)} байт")
    # Вызывающий может что-то делать между блоками

Состояние и память

Функция: нет состояния между вызовами

def counter():
    x = 0
    x += 1
    return x

print(counter())  # 1
print(counter())  # 1 (x снова 0)
print(counter())  # 1 (x снова 0)

Корутина (генератор): помнит состояние

def counter_coroutine():
    x = 0
    while True:
        x += 1
        yield x  # Помнит x между yield'ами

cor = counter_coroutine()
print(next(cor))  # 1
print(next(cor))  # 2 (x остался 1, теперь стал 2)
print(next(cor))  # 3 (x остался 2, теперь стал 3)

Асинхронные корутины (async/await)

Проблема: обычные функции блокируют

import time

def fetch_data(url):
    time.sleep(5)  # БЛОКИРУЕТ, ничего не может делать
    return "data"

print(fetch_data('http://api.com'))  # Ждём 5 секунд
print("Дальше...")  # Это выполнится только через 5 сек

Решение: асинхронные корутины

import asyncio
import aiohttp

async def fetch_data(url):
    async with aiohttp.ClientSession() as session:
        async with session.get(url) as resp:
            return await resp.text()  # ОТДАЁТ управление, не блокирует

async def main():
    task1 = fetch_data('http://api1.com')
    task2 = fetch_data('http://api2.com')
    task3 = fetch_data('http://api3.com')
    
    # Выполняются ПАРАЛЛЕЛЬНО, а не последовательно
    results = await asyncio.gather(task1, task2, task3)
    return results

asyncio.run(main())  # 1 вызов вместо 3 * 5сек

Синтаксис

Обычная функция:

def add(a, b):
    return a + b

result = add(5, 3)

Генератор (простая корутина):

def countdown(n):
    while n > 0:
        yield n
        n -= 1

for num in countdown(3):  # 3, 2, 1
    print(num)

Асинхронная корутина:

async def fetch_user(user_id):
    data = await get_from_api(f'/users/{user_id}')
    return data

user = asyncio.run(fetch_user(1))

Сравнительная таблица

ХарактеристикаФункцияКорутина
Управление потокомПоследовательноеМожет приостанавливаться
Состояние между вызовамиНетДа (сохраняется)
БлокированиеБлокируетasync не блокирует
ПараллелизмНевозможен (без многопоточности)Возможен
Синтаксисdef func()def func(): yield или async def func()
Использование памятиO(1) на вызовO(n) на все значения
Лениво вычисляетНетДа (вычисляет по требованию)

Практический пример

# Обработка больших данных

# ❌ Функция — грузит всё в память
def read_all_lines(filename):
    with open(filename) as f:
        return f.readlines()  # 1GB файл -> 1GB в памяти

for line in read_all_lines('huge.txt'):
    process(line)  # Всё уже в памяти

# ✅ Корутина — ленивая обработка
def read_lines(filename):
    with open(filename) as f:
        for line in f:  # Читает по одной строке
            yield line.strip()

for line in read_lines('huge.txt'):
    process(line)  # Обрабатывает на ходу, экономит память
# Асинхронность

# ❌ Функция блокирует
def get_users():
    user1 = requests.get('api/users/1').json()
    user2 = requests.get('api/users/2').json()
    user3 = requests.get('api/users/3').json()
    return [user1, user2, user3]  # Ждём 3 * 1сек = 3 сек

# ✅ Корутина параллелит
async def get_users():
    results = await asyncio.gather(
        fetch('api/users/1'),
        fetch('api/users/2'),
        fetch('api/users/3')
    )
    return results  # Всё параллельно, 1 сек вместо 3

Заключение

Функция — это механизм повторного использования кода. Выполняется полностью, потом забывается.

Корутина — это механизм управления потоком выполнения. Может приостанавливаться, помнит состояние, позволяет параллелизм без многопоточности.

Для интервью помни: Корутины решают две проблемы: 1) ленивое вычисление для экономии памяти, 2) асинхронность без многопоточности.

В чем разница между корутиной и функцией? | PrepBro