Почему asyncio делает запрос с aiohttp по-прежнему использует поток

Я думал, что ayncio, а использование coroutine не связано с потоком, поскольку coroutine — это тип «потока», работающего в планировщике программы, поэтому должен быть только 1 поток, выполняющий каждый процесс. Но когда я запустил примеры в https://pawelmhm.github.io/asyncio/python/aiohttp/2016/04/22/asyncio-aiohttp.html код выглядит следующим образом:

# modified fetch function with semaphore
import random
import asyncio
from aiohttp import ClientSession

async def fetch(url, session):
    async with session.get(url) as response:
        delay = response.headers.get("DELAY")
        date = response.headers.get("DATE")
        print("{}:{} with delay {}".format(date, response.url, delay))
        return await response.read()


async def bound_fetch(sem, url, session):
    # Getter function with semaphore.
    async with sem:
        await fetch(url, session)


async def run(r):
    url = "http://localhost:8080/{}"
    tasks = []
    # create instance of Semaphore
    sem = asyncio.Semaphore(1000)

    # Create client session that will ensure we dont open new connection
    # per each request.
    async with ClientSession() as session:
        for i in range(r):
            # pass Semaphore and session to every GET request
            task = asyncio.ensure_future(bound_fetch(sem, url.format(i), session))
            tasks.append(task)

        responses = asyncio.gather(*tasks)
        await responses

number = 10000
loop = asyncio.get_event_loop()

future = asyncio.ensure_future(run(number))
loop.run_until_complete(future)

С монитором ресурсов Windows я обнаружил, что код создает 25 потоков в 1 процессе.


person zl2003cn    schedule 21.02.2017    source источник


Ответы (2)


Библиотека aiohttp по умолчанию использует потоки для параллельного разрешения DNS, чтобы не блокировать цикл ввода-вывода, см. https://github.com/aio-libs/aiohttp/blob/master/aiohttp/resolver.py. Если вам нужен асинхронный поиск DNS, вам нужно установить пакет Python aiodns, который, в свою очередь, использует pycares.

Затем вы можете сделать:

async def fetch(url):
    resolver = aiohttp.AsyncResolver()
    connector = aiohttp.TCPConnector(resolver=resolver, family=socket.AF_INET)
    async with aiohttp.ClientSession(connector=connector) as session:
        async with session.get(url) as resp:
            if resp.status == 200:
                print("success!")

Если вы хотите установить AsyncResolver в качестве глобального по умолчанию, это сработало для меня с aiohttp 2.2.3:

import aiohttp.resolver
aiohttp.resolver.DefaultResolver = aiohttp.resolver.AsyncResolver
person hruske    schedule 18.07.2017

Стандартная библиотека Python включает модуль под названием threading, который позволяет одновременно запускать код Python с помощью используя Thread экземпляров. asyncio и aiohttp не используют модуль threading для работы.

Сам Python может использовать потоки ОС (низкоуровневые) в качестве детали реализации, но это, вероятно, зависит от разных платформ и версий. Например, количество потоков ОС для простого print('hello world'); s = input() для python 3.6.0 в Windows 10 равно 3.

Проверьте https://github.com/python/cpython/blob/3.6/Lib/asyncio/windows_events.py, чтобы найти подсказки о том, что может запускать потоки ОС в Windows.

person Udi    schedule 21.02.2017