async-await函数中的Python asyncio.semaphore

时间:2016-11-28 03:34:03

标签: python semaphore python-3.5 python-asyncio python-3.6

我正在尝试自学Python的异步功能。为此,我构建了一个异步Web scraper。我想限制我一次打开的连接总数,以成为服务器上的好公民。我知道信号量是一个很好的解决方案,而asyncio库内置了semaphore类。我的问题是Python在yield from函数中使用async时抱怨您正在组合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

提出此例外:

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

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

  1. 只需使用@asyncio.coroutine装饰器
  2. 即可
  3. 使用线程。信号量?这似乎可能会导致其他问题
  4. this为理由在Python 3.6的测试版中试用。
  5. 我对Python的异步功能非常陌生,所以我可能会遗漏一些明显的东西。

2 个答案:

答案 0 :(得分:8)

您可以使用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"))

取自here的示例。该页面也是asyncioaiohttp的良好入门。

答案 1 :(得分:2)

好的,所以这真的很傻但我只是用信号量上下文管理器中的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