Есть ли линтер, который обнаруживает блокирующие вызовы в асинхронной функции? - PullRequest
1 голос
/ 01 мая 2019

https://www.aeracode.org/2018/02/19/python-async-simplified/

Это не испортит ваш день, если вы называете неблокирующую синхронную функция, как это:

def get_chat_id(name):
    return "chat-%s" % name

async def main():
    result = get_chat_id("django")

Однако, если вы вызываете блокирующую функцию, такую ​​как Django ORM, код внутри асинхронной функции будет выглядеть идентично, но теперь это опасный код, который может заблокировать весь цикл событий, так как он не в ожидании:

def get_chat_id(name):
    return Chat.objects.get(name=name).id

async def main():
    result = get_chat_id("django")

Вы можете видеть, как легко иметь неблокирующую функцию, которая «случайно» становится блокирующим, если программист не знает все, что это вызывает. Вот почему я рекомендую вам никогда не звонить что-нибудь синхронное из асинхронной функции, не делая это безопасно, или не зная заранее, что это неблокирующая стандартная библиотека функция, как os.path.join.

Так что я ищу способ автоматически ловить случаи этой ошибки. Есть ли в Python линтеры, которые будут сообщать о вызовах функций синхронизации из асинхронной функции как о нарушении?

Могу ли я настроить Pylint или Flake8 для этого?

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


Обновление:

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

Поэтому для целей этого вопроса я даю следующее определение:

«Опасная синхронная функция» - это та, которая выполняет операции ввода-вывода. Это те же самые операции, которые, например, должны быть пропатчены с помощью gevent, или которые должны быть заключены в функции async, чтобы цикл обработки событий мог переключать контекст.

(я бы приветствовал любое уточнение этого определения)

1 Ответ

1 голос
/ 01 мая 2019

Итак, я ищу способ автоматически перехватывать экземпляры этой ошибки.

Давайте сделаем несколько ясных вещей: ошибка, обсуждаемая в статье, заключается в том, что вы вызываете любую долго выполняющуюся функцию синхронизации внутринекоторая сопрограмма asyncio (это может быть вызов блокировки ввода-вывода или просто функция CPU с большим количеством вычислений).Это ошибка, потому что она заблокирует весь цикл обработки событий, что приведет к значительному снижению производительности (подробнее об этом здесь , включая комментарии ниже).

Есть ли способ автоматически уловить эту ситуацию?До времени выполнения - нет, никто, кроме вас, не может предсказать, будет ли выполнение определенной функции 10 секунд или 0,01 секунды.Во время выполнения это уже встроенный asyncio , все, что вам нужно сделать, это включить режим отладки.

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

...