async-await函数中的Python asyncio.semaphore

Bru*_*cci 6 python semaphore python-asyncio python-3.5 python-3.6

我正在尝试自学Python的异步功能.为此,我构建了一个异步Web scraper.我想限制我一次打开的连接总数,以成为服务器上的好公民.我知道信号量是一个很好的解决方案,并且asyncio库内置了一个信号量类.我的问题是,当你在组合和语法yield from中使用async函数时,Python会抱怨.以下是我正在使用的确切语法...yieldawait

import asyncio
import aiohttp

sema = asyncio.BoundedSemaphore(5)

async def get_page_text(url):
    with (yield from sema):
        try:
            resp = await aiohttp.request('GET', url)
            if resp.status == 200:
                ret_val = await resp.text()
        except:
            raise ValueError
        finally:
            await resp.release()
    return ret_val
Run Code Online (Sandbox Code Playgroud)

提出这个例外:

File "<ipython-input-3-9b9bdb963407>", line 14
    with (yield from sema):
         ^
SyntaxError: 'yield from' inside async function
Run Code Online (Sandbox Code Playgroud)

我能想到的一些可能的解决方案......

  1. 只需使用@asyncio.coroutine装饰器
  2. 使用threading.Semaphore?这似乎可能会导致其他问题
  3. 在Python 3.6的测试版试试这个这个原因.

我是Python的异步功能的新手,所以我可能会遗漏一些明显的东西.

Seb*_*zny 10

您可以使用该async with语句来获取异步上下文管理器:

#!/usr/local/bin/python3.5
import asyncio
from aiohttp import ClientSession


sema = asyncio.BoundedSemaphore(5)

async def hello(url):
    async with ClientSession() as session:
        async with sema, session.get(url) as response:
            response = await response.read()
            print(response)

loop = asyncio.get_event_loop()
loop.run_until_complete(hello("http://httpbin.org/headers"))
Run Code Online (Sandbox Code Playgroud)

从这里取的例子.该页面也是一个很好的入门asyncio和aiohttp一般.


Bru*_*cci 6

好的,所以这真的很愚蠢,但我只是在信号量上下文管理器中替换yield from了await它,它运行良好。

sema = asyncio.BoundedSemaphore(5)

async def get_page_text(url):
    with (await sema):
        try:
            resp = await aiohttp.request('GET', url)
            if resp.status == 200:
                ret_val = await resp.text()
        except:
            raise ValueError
        finally:
            await resp.release()
    return ret_val
Run Code Online (Sandbox Code Playgroud)

  • 更好的是,您可以使用 `async with` 语句:`async with sema: [...]` (7认同)