为什么asyncio使用aiohttp发出请求仍然使用线程

时间:2017-02-21 01:04:06

标签: python python-asyncio aiohttp

我认为ayncio并且使用coroutine与线程无关,因为coroutine是一种"线程"在程序的调度程序下运行,因此每个进程只应运行一个线程。但是当我在Making 1 million requests with python-aiohttp中运行示例时,代码如下所示:

# 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'资源监视器,我发现代码在1个进程中创建了25个线程。

2 个答案:

答案 0 :(得分:2)

aiohttp库默认使用线程进行并发DNS解析,以免阻塞IO循环,请参阅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

答案 1 :(得分:1)

Python的标准库包含一个名为threading的模块,它允许使用$(document).ready(function (){ var table = $('#example').DataTable({ dom: 'lrtip', initComplete: function () { this.api().columns([2]).every( function () { var column = this; console.log(column); var select = $("#officeFltr"); column.data().unique().sort().each( function ( d, j ) { select.append( '<option value="'+d+'">'+d+'</option>' ) } ); } ); this.api().columns([3]).every( function () { var column = this; console.log(column); var select = $("#ageFltr"); column.data().unique().sort().each( function ( d, j ) { select.append( '<option value="'+d+'">'+d+'</option>' ) } ); } ); $("#officeFltr,#ageFltr").material_select(); } }); $('#officeFltr').on('change', function(){ var search = []; $.each($('#officeFltr option:selected'), function(){ search.push($(this).val()); }); search = search.join('|'); table.column(2).search(search, true, false).draw(); }); $('#ageFltr').on('change', function(){ var search = []; $.each($('#ageFltr option:selected'), function(){ search.push($(this).val()); }); search = search.join('|'); table.column(3).search(search, true, false).draw(); }); }); 实例同时运行python代码。 Threadasyncio不使用aiohttp模块进行操作。

Python本身可能会使用OS(低级)线程作为实现细节 - 但这可能会在不同平台和版本之间发生变化。例如,Windows 10中python 3.6.0的简单threading的OS线程数为3。

查看https://github.com/python/cpython/blob/3.6/Lib/asyncio/windows_events.py以查找可能在Windows中启动操作系统线程的线索。