4

2 つのハンドラーを持つ単純な aiohttp-server があります。async forまず、ループ内でいくつかの計算を行います。2 つ目は、テキスト応答を返すだけです。not_so_long_operation再帰的な実装が最も遅く、約 1 秒かかる 30 番目のフィボナッチ数を返します。

def not_so_long_operation():
    return fib(30)

class arange:
    def __init__(self, n):
        self.n = n
        self.i = 0

    async def __aiter__(self):
        return self

    async def __anext__(self):
        i = self.i
        self.i += 1
        if self.i <= self.n:
            return i
        else:
            raise StopAsyncIteration

# GET /
async def index(request):
    print('request!')
    l = []
    async for i in arange(20):
        print(i)
        l.append(not_so_long_operation())

    return aiohttp.web.Response(text='%d\n' % l[0])

# GET /lol/
async def lol(request):
    print('request!')
    return aiohttp.web.Response(text='just respond\n')

/フェッチしてから を取得しようとすると/lol/、最初のものが終了したときにのみ、2 番目の応答が返されます。
私は何を間違っていますか? また、反復ごとにインデックス ハンドラーが ioloop を解放する方法を教えてください。

4

3 に答える 3

2

ここでは、非同期反復子は実際には必要ありません。代わりに、ループ内のイベント ループに制御を戻すことができます。Python 3.4 では、これは単純な を使用して行われyieldます。

@asyncio.coroutine
def index(self):
    for i in range(20):
        not_so_long_operation()
        yield

EmptyPython 3.5 では、基本的に同じことを行うオブジェクトを定義できます。

class Empty:
    def __await__(self):
        yield

次に、await構文で使用します。

async def index(request):
    for i in range(20):
        not_so_long_operation()
        await Empty()

または、最近最適化されたasyncio.sleep(0)を使用するだけです。

async def index(request):
    for i in range(20):
        not_so_long_operation()
        await asyncio.sleep(0)

デフォルトの executornot_so_long_operationを使用して、スレッドで実行することもできます。

async def index(request, loop):
    for i in range(20):
        await loop.run_in_executor(None, not_so_long_operation)
于 2015-11-04T13:41:51.660 に答える