Асинхронное программирование 101: что это такое Попробуйте Python asyncio

Python

Что такое асинхронное программирование?

Примечание: Одновременно в этой статье упоминается интуитивно прочувствованное понятие, просто для упрощения, не одно и то же в строгом смысле.

Мы все знакомы с синхронным кодом, который заключается в выполнении одного шага перед выполнением следующего. Самый простой и интуитивно понятный способ «одновременного» выполнения нескольких задач в синхронном коде — запустить несколько потоков или несколько процессов.«Одновременному запуску» нескольких задач на этом уровне помогает операционная система.То есть система планирования задач операционной системы определяет, когда запускать эту задачу и когда переключать задачи.Вы, как программист прикладного уровня, не имеете возможности вмешиваться.

Я уверен, что вы слышали некоторые жалобы на потоки и процессы: процессы слишком тяжелые, а потоки связаны с множеством проблем с блокировкой заголовков. Особенно для разработчика Python, посколькуGILналичие (глобальной блокировки интерпретатора),Многопоточность на самом деле не может использовать несколько ядер, если вы используете несколько потоков для выполнения вычислительных задач, это будет медленнее.

Асинхронное программирование отличается тем, что оно использует процесс и не использует потоки, но оно также может запускать несколько задач «одновременно» (задачи здесь на самом деле являются функциями).

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

Вопросы асинхронного программирования

Есть одна вещь, которая требует особого внимания,Блочные функции не должны использоваться в асинхронном коде.! То есть в вашем коде не должно быть следующего:

  • time.sleep()
  • Блокирующий сокет
  • requests.get()
  • Блокировка обращений к базе данных

Зачем?При использовании потока или процесса код блокирует операционную систему, чтобы помочь вам планировать, поэтому не будет ситуации «один блок, везде глупо».

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

Небольшой тест Python asyncio

Поддержка версии Python

  • Модуль asyncio был выпущен с Python 3.4.
  • Ключевые слова async и await были впервые представлены в Python 3.5.
  • Не поддерживается до Python 3.3.

Начните вводить код

Синхронизировать версию

Это просто посетить домашнюю страницу Baidu 100 раз, а затем распечатать код состояния.

import time
import requests

def visit_sync():
    start = time.time()
    for _ in range(100):
        r = requests.get(URL)
        print(r.status_code)
    end = time.time()
    print("visit_sync tasks %.2f seconds" % (end - start))

if __name__ == '__main__':
    visit_sync()

Запустите его и нашли использование 6,64 секунды.

Асинхронная версия

import time
import asyncio
import aiohttp

async def fetch_async(url):
    async with aiohttp.ClientSession() as session:
        async with session.get(url) as resp:
            status_code = resp.status
            print(status_code)


async def visit_async():
    start = time.time()
    tasks = []
    for _ in range(100):
        tasks.append(fetch_async(URL))
    await asyncio.gather(*tasks)
    end = time.time()
    print("visit_async tasks %.2f seconds" % (end - start))


if __name__ == '__main__':
    loop = asyncio.get_event_loop()
    loop.run_until_complete(visit_async())

Несколько моментов для уточнения:

  • Изменилась часть сетевого доступа, прежний — request.get(), а здесь — aiohttp (не стандартная библиотека, нужно ставить самому).
  • Изменился способ вызова функции, предыдущий проходvisit_sync()Вы можете запустить его напрямую, но вы не можете запустить его напрямую в асинхронном коде.visit_async()Это предложит вам ПРЕДУПРЕЖДЕНИЕ:

Если вы печатаетеvisit_async()Видно тип возвращаемого значения, это сопрограмма (coroutine).

Нормальная поза - звонитьawait visit_async(), как в кодеawait asyncio.gather(*tasks)Такой же. Но хлопотнее всегоawaitтолько по ключевым словамasyncиспользуется внутри определенной функции, и нашif __name__ == "__main__"Функций в нем нет, так что можно поставить вот этоcoroutineПереход к циклу событий.

loop = asyncio.get_event_loop()
loop.run_until_complete(visit_async())

После запуска выяснилось, что это заняло 0,34 секунды, а эффективность увеличилась более чем в 20 раз. (О том, как принудительно анализировать асинхронную эффективность, вы можете обратиться к предыдущей статье.статья. )

В заключение

Фактически, эта статья уже ввела важную концепцию в асинхронном программировании: COROUTINES. «Асинхронное программирование 101» серия статей потратит много времени, говорят о CONOTINES позже.

Основа для COROUTINE для запуска нескольких задач «одновременно»функция может быть приостановлена(Мы увидим, как это делается позже, в Python через yield). используется в приведенном выше кодеasyncioEvent_loop, что он делает, по сути, когда функция приостановлена, она переключается на следующую задачу, а когда подходит время (в данном случае запрос выполнен), возобновляет функцию и позволяет ей продолжать работу (это немного похоже на операционную систему).

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

Лично я считаю, что у программистов новой эры есть два очень важных навыка:Возможность асинхронного программирования и использования преимуществ многоядерных систем.

Думаете, хорошо иметь звезду?

Мой официальный аккаунт: Полный стек не существует