web-dev-qa-db-ja.com

Python asyncio.semaphoreのasync-await関数

私はPythonの非同期機能を自分自身に教えようとしています。そうするために、私は非同期Webスクレイパーを構築しました。サーバー上で善良な市民になるために、一度に開く接続の総数を制限したいと思います。セマフォが良い解決策であることを私は知っています、そしてasyncioライブラリには セマフォ クラスが組み込まれています。私の問題はPythonでyield fromを使用すると文句を言うことですasync構文とyield構文を組み合わせたときのawait関数。以下は私が使用している正確な構文です...

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. Threading.Semaphoreを使用しますか?これは他の問題を引き起こす可能性があるようです
  3. これをPython 3.6のベータ版で this の理由で試してください。

私はPythonの非同期機能に非常に慣れていないので、明らかな何かが欠けている可能性があります。

7
Bruce Pucci

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"))

ここ からの例。このページは、一般的にasyncioおよびaiohttpの入門書としても適しています。

11
Sebastian Wozny

OK、これは本当にばかげていますが、セマフォコンテキストマネージャーでyield fromawaitに置き換えるだけで、完全に機能しています。

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
2
Bruce Pucci