Почему я могу использовать только ключевое слово await внутри асинхронной функции?

1

Предположим, у меня есть такой код

async def fetch_text() -> str:
    return "text "

async def show_something():
    something = await fetch_text()
    print(something)

Это нормально. Но тогда я хочу очистить данные, поэтому я делаю

async def fetch_text() -> str:
    return "text "

def fetch_clean_text(text: str) -> str:
    text = await fetch_text()
    return text.strip(text)

async def show_something():
    something = fetch_clean_text()
    print(something)

(Я мог бы очистить текст внутри show_something(), но предположим, что show_something() может печатать много вещей и не знает или не должен знать, как правильно их очистить).

Это, конечно, SyntaxError: 'await' outside async function. Но если этот код мог бы работать, в то время как выражение await не помещается внутри функции сопрограммы, оно выполняется в контексте одного. Почему это поведение запрещено?

В этом дизайне я вижу одного профессионала; в моем последнем примере вы не можете видеть, что show_something() делает что-то, что может привести к его приостановке. Но если бы я сделал fetch_clean_text() сопрограмму, это не только усложнило бы ситуацию, но, вероятно, также снизило бы производительность. Просто не имеет смысла иметь другую сопрограмму, которая не выполняет никаких операций ввода-вывода. Есть ли способ лучше?

  • 1
    Итак, что же на самом деле мешает вам очистить текст чистой функцией после того, как вы его получили?
  • 0
    Короче говоря, нормальная функция не может быть запланирована, но await расписание. Как указано выше, вы можете использовать чистую функцию после извлечения.
Показать ещё 1 комментарий
Теги:
python-asyncio

1 ответ

1
Лучший ответ

В этом дизайне я вижу одного профессионала; в моем последнем примере вы не можете видеть, что тело show_something() делает что-то, что может привести к его приостановке.

Именно поэтому он и разработал этот путь. Написание параллельного кода может быть очень сложным, и авторы асинхронно решили, что критически важно всегда явно отмечать места приостановки кода.

В этой статье это подробно объясняется (вы можете начать с пункта "Get To The Point Already").

Но если бы я сделал fetch_clean_text() сопрограмму, это не только усложнило бы ситуацию, но, вероятно, также снизило бы производительность.

Вам нужны сопрограммы почти исключительно, когда вы имеете дело с I/O. Для ввода сопрограмм ввода-вывода всегда требуется гораздо больше времени, чем накладные расходы. Поэтому я думаю, это можно сказать - нет, по сравнению с I/O, с которым вы уже имеете дело, вы не потеряете сколько-нибудь значительного времени для использования сопрограмм.

Есть ли способ лучше?

Единственный способ, который я могу предложить: - максимально разделить логику, связанную с I/O (асинхронной частью) с остальной частью кода (часть синхронизации).

from typing import Awaitable

def clean_text(text: str) -> str:
    return text.strip(text)

async def fetch_text() -> Awaitable[str]:
    return "text "

async def fetch_clean_text(text: str) -> Awaitable[str]:
    text = await fetch_text()
    return clean_text(text)

async def show_something():
    something = await fetch_clean_text()
    print(something)

Ещё вопросы

Сообщество Overcoder
Наверх
Меню