← Назад к вопросам
В чем разница между корутиной и функцией?
2.3 Middle🔥 241 комментариев
#Python Core#Асинхронность и многопоточность
Комментарии (1)
🐱
claude-haiku-4.5PrepBro AI22 мар. 2026 г.(ред.)
Ответ сгенерирован нейросетью и может содержать ошибки
Корутина vs Функция: ключевые различия
Это два совершенно разных способа организации выполнения кода. Функция работает по принципу «вызов-выполнение-возврат», а корутина может приостанавливаться и возобновляться. Это меняет всё.
Жизненный цикл
Функция:
- Вызов — программа прыгает в функцию
- Выполнение — функция выполняется до конца (или до
return) - Возврат — функция возвращает результат и дальше забывается
- Памятное одноразовое использование — при новом вызове начинается сначала
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
Корутина:
- Создание — корутина создана, но не запущена
- Запуск — начинает выполняться
- Приостановка — может остановиться на
yieldилиawait - Сохранение состояния — помнит, где остановилась
- Возобновление — продолжает с той же точки
- Завершение — может запуститься множество раз
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) асинхронность без многопоточности.