Эта статья была впервые опубликована вЗнай почти
Асинхронный — это третий способ достижения параллелизма после многопоточности и многопроцессорности, который в основном используется для повышения эффективности выполнения задач с интенсивным вводом-выводом. Асинхронность в питоне основана наyield
Генератор, прежде чем объяснять эту часть принципа, сначала изучим использование асинхронной библиотеки asyncio.
В этой статье в основном объясняетсяasyncio
Для большинства модулей использование некоторых подробностей функций просто пропускается.
Эта статья разделена на следующие части
- Простое использование
- Другое распространенное использование
- один вопрос
- Асинхронный по общей функции
- Понимание асинхронности, сопрограмм
- Асинхронный сканер с одним потоком
Самый простой в использовании
import asyncio
async def myfun(i):
print('start {}th'.format(i))
await asyncio.sleep(1)
print('finish {}th'.format(i))
loop = asyncio.get_event_loop()
myfun_list = (myfun(i) for i in range(10))
loop.run_until_complete(asyncio.gather(*myfun_list))
Таким образом, 10 ожиданий составляют всего 1 секунду.
Просто запомните некоторые общепринятые способы использования приведенного выше кода, такие как
- Чтобы запустить функцию асинхронно, вам нужно добавить к определению функции префикс
async
- Просто запомните последние три строки, а затем передайте функцию
Другое распространенное использование
Вышеупомянутое является первым распространенным использованием, следующее - другое
import asyncio
async def myfun(i):
print('start {}th'.format(i))
await asyncio.sleep(1)
print('finish {}th'.format(i))
loop = asyncio.get_event_loop()
myfun_list = [asyncio.ensure_future(myfun(i)) for i in range(10)]
loop.run_until_complete(asyncio.wait(myfun_list))
Разница между этим использованием и приведенным выше состоит в том, что более поздний вызовasyncio.gather
все ещеasyncio.wait
, в настоящее время его можно считать полностью эквивалентным, поэтому вы можете использовать любой из вышеперечисленных способов при обычном использовании.
Выше приведены два наиболее часто используемых метода, перечисленных здесь, чтобы читатели не запутались при чтении других статей.
Кроме того, есть тонкие различия между двумя
-
gather
Лучше агрегировать функции вместе -
wait
Лучше фильтровать состояния здоровья
Подробности можно посмотретьэтот ответ
один вопрос
По сравнению с многопоточностью и многопроцессорностью, изученными ранее,asyncio
У модулей есть одно очень большое отличие: передаваемая функция не является произвольной.
- Например, мы положили выше
myfun
в функцииsleep
заменитьtime.sleep(1)
, время выполнения не асинхронное, а синхронное, ожидание всего 10 секунд - если я поменяю один
myfun
, например, используйте следующееrequest
функция сканирования веб-страниц
import asyncio
import requests
from bs4 import BeautifulSoup
async def get_title(a):
url = 'https://movie.douban.com/top250?start={}&filter='.format(a*25)
r = requests.get(url)
soup = BeautifulSoup(r.content, 'html.parser')
lis = soup.find('ol', class_='grid_view').find_all('li')
for li in lis:
title = li.find('span', class_="title").text
print(title)
loop = asyncio.get_event_loop()
fun_list = (get_title(i) for i in range(10))
loop.run_until_complete(asyncio.gather(*fun_list))
Все еще не выполняется асинхронно.
В этот момент мы подумаем, определена ли асинхронность только для себя?sleep
(await asyncio.sleep(1)
) для запуска асинхронности?
Асинхронный по общей функции
Для вышеуказанной функцииasyncio
Библиотека может добиться асинхронности только добавлением потоков, реализуем это ниже.time.sleep
асинхронный
import asyncio
import time
def myfun(i):
print('start {}th'.format(i))
time.sleep(1)
print('finish {}th'.format(i))
async def main():
loop = asyncio.get_event_loop()
futures = (
loop.run_in_executor(
None,
myfun,
i)
for i in range(10)
)
for result in await asyncio.gather(*futures):
pass
loop = asyncio.get_event_loop()
loop.run_until_complete(main())
вышеrun_in_executor
Фактически открывается новый поток, а затем координируются различные потоки. Процесс вызова более сложен, если он применяется в качестве шаблона.
Вышеуказанные 10 петель все же распечатываются не за один раз, а пачками. Это потому, что недостаточно потоков для открытия.Если вы хотите печатать за один раз, вы можете открыть 10 потоков.Код выглядит следующим образом
import concurrent.futures as cf # 多加一个模块
import asyncio
import time
def myfun(i):
print('start {}th'.format(i))
time.sleep(1)
print('finish {}th'.format(i))
async def main():
with cf.ThreadPoolExecutor(max_workers = 10) as executor: # 设置10个线程
loop = asyncio.get_event_loop()
futures = (
loop.run_in_executor(
executor, # 按照10个线程来执行
myfun,
i)
for i in range(10)
)
for result in await asyncio.gather(*futures):
pass
loop = asyncio.get_event_loop()
loop.run_until_complete(main())
добиться этогоrequests
Код асинхронного сканера выглядит следующим образом
import concurrent.futures as cf
import asyncio
import requests
from bs4 import BeautifulSoup
def get_title(i):
url = 'https://movie.douban.com/top250?start={}&filter='.format(i*25)
r = requests.get(url)
soup = BeautifulSoup(r.content, 'html.parser')
lis = soup.find('ol', class_='grid_view').find_all('li')
for li in lis:
title = li.find('span', class_="title").text
print(title)
async def main():
with cf.ThreadPoolExecutor(max_workers = 10) as executor:
loop = asyncio.get_event_loop()
futures = (
loop.run_in_executor(
executor,
get_title,
i)
for i in range(10)
)
for result in await asyncio.gather(*futures):
pass
loop = asyncio.get_event_loop()
loop.run_until_complete(main())
Эта часть справкиэта статьяиэтот ответ
Этот способ открытия нескольких потоков также является своего рода асинхронным, который подробно объясняется в следующем разделе.
Понимание асинхронности, сопрограмм
Теперь, когда мы рассмотрели некоторые варианты использования асинхронности, пришло время объяснить некоторые концепции.
- Во-первых, мы должны понятьСинхронный, асинхронный, блокирующий, неблокирующийСвязь между четырьмя словами
- Прежде всего, должно быть понятно, что первые два и последние два не являются однозначным соответствием, они не говорят об одном и том же, но очень похожи, их легко спутать.
- Обычно мы говорим, что асинхронные программы являются неблокирующими, тогда как синхронные программы являются как блокирующими, так и неблокирующими.
- Неблокировка означает, что задача не завершена, нет необходимости останавливаться на достигнутом и ждать ее завершения, прежде чем начинать следующую задачу, гарантируя, что она работала без ожидания; блокировка — это противоположность того, что одна вещь полностью завершена до начала Другая
- В неблокирующем случае возможны как синхронные, так и асинхронные задачи, каждая из которых может запустить следующую задачу до ее завершения. Разница между ними заключается в следующем: (и текущая программа называется основной программой), когда первая программа завершается (например, сетевой запрос, наконец, отвечает), она автоматически уведомляет основную программу вернуться и продолжить работу результат первой задачи, это асинхронно, при этом синхронизация требует, чтобы основная программа постоянно спрашивала, выполнена ли первая программа.
- Разница между четырьмя словамиЗнать ответ
- (Разница между сопрограммой и многопоточностью) В неблокирующем случае многопоточность является представителем синхронизации, а сопрограмма — представителем асинхронности. Оба открывают несколько потоков
- В многопоточности несколько потоков будут соревноваться за то, кто запустится первым, и один не уведомит основную программу об окончании ожидания, поэтому случайная работа без правил приведет к некоторой трате ресурсов
- В сопрограммах вызовы и ожидания нескольких потоков (называемых микропотоками) организованы явным кодом. Сопрограммы подобны цели выполнения одной задачи за другой, в то время как многопоточность имеет некоторое колеблющееся время.
- два вида асинхронности
- В предыдущих разделах речь шла о двух видах асинхронности.
await
Переключение задач может быть достигнуто с использованием только одного потока, а другой - разрешить нескольким потокам достичь асинхронности посредством планирования потоков. - Как правило, для переключения задач между несколькими функциями используется только один поток, который реализуется с помощью генератора доходности.Эта статья, наконец, приводит потребительский пример
- Многопроцессный, многопоточный, асинхронный, хороший в направлении
- Асинхронность и многопоточность имеют очевидные преимущества в задачах с интенсивным вводом-выводом, поскольку их суть заключается в том, чтобы попытаться избежать потери ресурсов, вызванной временем ожидания ввода-вывода. И многопроцессорность может использовать преимущества многоядерности, подходящей для задач с интенсивным использованием ЦП.
- По сравнению с многопоточностью асинхронность больше подходит для программ, которые каждый раз долго ждут и требуют ожидания большего количества задач. Поскольку многопоточность в конце концов должна создавать новые потоки, слишком большое количество потоков делает конкуренцию потоков более очевидной, и больше ресурсов тратится впустую. Если время ожидания для каждой задачи слишком велико, во время ожидания будет открыто много задач и потоков.В настоящее время использование многопоточности не является мудрым решением. С другой стороны, асинхронный может открыть только один поток для упорядоченного выполнения различных задач, то есть он может полностью использовать ресурсы ЦП, не влияя на эффективность программы.
Асинхронный сканер с одним потоком
Вышеупомянутое достигается путем открытия нескольких потоковrequests
асинхронный, если мы хотим использовать только один поток (сawait
), необходимо изменить функцию запроса веб-страницы.
На самом деле, чтобы использоватьawait
, должен быть ожидаемым объектом, который нельзя использоватьrequests
причина. Конечно, нам не нужно реализовывать такие вещи, как преобразование в ожидаемые объекты.aiohttp
Модули могут преобразовывать запросы веб-страниц иasyncio
Модули идеально соединены. Используйте этот модуль, чтобы переписать код следующим образом
import asyncio
import aiohttp
from bs4 import BeautifulSoup
async def get_title(i):
url = 'https://movie.douban.com/top250?start={}&filter='.format(i*25)
async with aiohttp.ClientSession() as session:
async with session.get(url) as resp:
print(resp.status)
text = await resp.text()
print('start', i)
soup = BeautifulSoup(text, 'html.parser')
lis = soup.find('ol', class_='grid_view').find_all('li')
for li in lis:
title = li.find('span', class_="title").text
print(title)
loop = asyncio.get_event_loop()
fun_list = (get_title(i) for i in range(10))
loop.run_until_complete(asyncio.gather(*fun_list))
Добро пожаловать, чтобы обратить внимание на мою колонку знаний
Главная страница колонки:программирование на питоне
Каталог столбцов:содержание
Примечания к выпуску:Примечания к выпуску программного обеспечения и пакетов