2017-08-21 3 views
1
私はasyncioループ内で、将来の結果を取得する必要があり

、それは完全に異なるCalling a coroutine from asyncio.Protocol.data_receivedコルーチンを呼び出して、将来asyncio.Protocol.data_received()で取得しますか?

しかし、PY35とPY34でasyncioに似ているで、ここPY34で正しく実行できるコードですが、PY35にそれがで一時停止しますyield fromと決して戻ってきません。

# PY34 
class RelayClient(asyncio.Protocol): 
    pass 

class Server(asyncio.Protocol): 
    def data_received(self, data): 
     # I need to connect to another address, and get future result at current function. 
     # Also I could not run loop.run_until_complete(). 
     loop = asyncio.get_event_loop() 
     result = yield from loop.create_connection(RelayClient, 'www.google.com', 443) 
     do_some_thing_with_result(result) 

これはどのようにpython 3.5で行うのですか?

アドバイスありがとうございます。

+0

[asyncio.Protocol.data \ _receivedからコルーチンを呼び出す]の可能な複製(https://stackoverflow.com/questions/29126340/calling-a-coroutine-from-asyncio-protocol-data-received) – kwarunek

+0

@kwarunek私の質問を更新する – hfawja

+0

問題は同じように見えます。 'Protocol.data_received'では' await'や 'yield from'を使うことはできません。代わりに' ensure_future'を使い、適切なコールバックを設定してください。 – kwarunek

答えて

1

コルーチンではない関数からコルーチンを待つことはできません。 data_receivedはコルーチンではないので、コメントに記載されているように、ensure_futureヘルパーを使用してコルーチンから「バックグラウンド」タスクを作成する必要があります。しかし、コールバックを使用して起動する

の必要はありません:

async def do_stuff(data): 
     result = await loop.create_connection(RelayClient, 'www.google.com', 443) 
     await do_some_thing_with_result(result) 

class Server(asyncio.Protocol): 
    def data_received(self, data): 
     asyncio.ensure_future(do_stuff(data)) 

を私はasyncioがdata_receivedは、あなたが期待している完全なデータと呼ばれることを全くgarantiesを与えないこと、しかし、指摘します。通常Protocolでご覧のパターンは、このようにたくさん見える:

async def process_line(line): 
    ... 

class Server(asyncio.Protocol): 
    def __init__(self): 
     self.buffer = b'' 

    def data_received(self, data): 
     self.buffer += data 

     if b'\n' not in self.buffer: 
      return 

     line, self.buffer = self.buffer.split(b'\n') 
     fut = asyncio.ensure_future(process_line(line)) 
     fut.add_done_callback(self._handle_exception) 

    def _handle_exception(self, fut): 
     if fut.exception() is not None: 
      print('Processing failed', fut.exception()) 

(これは、それがコピーバッファあまりにも多くの単なる一例であり、ほとんどの生産ユースケースで非常に効率が悪い)

+1

あなたはバッファコピーを避ける方法についていくつかヒントを与えることができますか? –

+1

異なるアプローチがあり、すべてに欠点があります。 asyncioフレームワーク自体は、バッファリングされたデータをあまりにも多くコピーすることなく、データを蓄積するために受け取るすべてのチャンクに対して 'buffer = bytearray()'を使用し、 'buffer.extend(data)'を呼び出します:https:// github。一方、aiohttpは 'buffer = []'アプローチを使用し、新しいチャンクは単にリストに追加されます(つまり、何もコピーされません)。com/python/cpython/blob/3.6/Lib/asyncio/streams.py#L424 – Arthur

+1

データが受信されたとき)、チャンクを最終的に正しく結合するためにコピーする必要があります:https://github.com/aio-libs/aiohttp/blob/master/aiohttp/streams.py#L284 – Arthur

関連する問題