tornado.gen — ジェネレータベースのコルーチン

tornado.gen は、ジェネレータベースのコルーチンを実装します。

注記

このモジュールにおける「デコレータとジェネレータ」のアプローチは、ネイティブコルーチン(async defawaitを使用)の前身であり、Python 3.5で導入されました。旧バージョンのPythonとの互換性を必要としないアプリケーションは、代わりにネイティブコルーチンを使用する必要があります。このモジュールのいくつかの部分は、ネイティブコルーチンでも依然として有用です。multisleepWaitIteratorwith_timeoutなどが特に挙げられます。これらの関数のいくつかはasyncioモジュールにも対応するものがありますが、必ずしも100%互換性があるとは限りません。

コルーチンは、コールバックを連鎖させるよりも、非同期環境で作業する簡単な方法を提供します。コルーチンを使用するコードは技術的には非同期ですが、複数の個別の関数のコレクションではなく、単一のジェネレータとして記述されます。

例として、コルーチンベースのハンドラーを示します。

class GenAsyncHandler(RequestHandler):
    @gen.coroutine
    def get(self):
        http_client = AsyncHTTPClient()
        response = yield http_client.fetch("http://example.com")
        do_something_with_response(response)
        self.render("template.html")

Tornadoの非同期関数はAwaitableまたはFutureを返します。このオブジェクトをyieldすると、その結果が返されます。

他のyield可能なオブジェクトのリストまたは辞書をyieldすることもできます。これらは同時に開始され、並列に実行されます。すべてが完了すると、結果のリストまたは辞書が返されます。

@gen.coroutine
def get(self):
    http_client = AsyncHTTPClient()
    response1, response2 = yield [http_client.fetch(url1),
                                  http_client.fetch(url2)]
    response_dict = yield dict(response3=http_client.fetch(url3),
                               response4=http_client.fetch(url4))
    response3 = response_dict['response3']
    response4 = response_dict['response4']

tornado.platform.twistedがインポートされている場合、TwistedのDeferredオブジェクトをyieldすることも可能です。このメカニズムを拡張するには、convert_yielded関数を参照してください。

バージョン 3.2 で変更されました: 辞書サポートが追加されました。

バージョン 4.1 で変更されました: singledispatchを介してasyncio FuturesとTwisted Deferredsのyieldサポートが追加されました。

デコレータ

tornado.gen.coroutine(func: Callable[[...], Generator[Any, Any, _T]]) Callable[[...], Future[_T]][source]
tornado.gen.coroutine(func: Callable[[...], _T]) Callable[[...], Future[_T]]

非同期ジェネレータのためのデコレータ。

旧バージョンのPythonとの互換性のために、コルーチンは特別な例外Return(value)を発生させることによっても「値を返す」ことができます。

このデコレータが付いた関数はFutureを返します。

警告

コルーチン内で例外が発生した場合、例外情報はFutureオブジェクトに格納されます。Futureオブジェクトの結果を検査する必要があります。そうしないと、例外がコードによって気付かれない可能性があります。これは、別のコルーチンから呼び出された場合にその関数をyieldすること、トップレベルの呼び出しにはIOLoop.run_syncのようなものを使用すること、またはFutureIOLoop.add_futureに渡すことを意味します。

バージョン 6.0 で変更されました: callback引数が削除されました。代わりに返されたawaitableオブジェクトを使用してください。

exception tornado.gen.Return(value: Optional[Any] = None)[source]

coroutineから値を返すための特別な例外。

この例外が発生すると、そのvalue引数がコルーチンの結果として使用されます。

@gen.coroutine
def fetch_json(url):
    response = yield AsyncHTTPClient().fetch(url)
    raise gen.Return(json_decode(response.body))

Python 3.3では、この例外は不要になりました。return文を直接使用して値を返すことができます(以前は、同じ関数内でyieldと値付きのreturnを組み合わせることができませんでした)。

return文との類推により、value引数はオプションですが、raise gen.Return()とする必要は決してありません。return文を引数なしで使用できます。

ユーティリティ関数

tornado.gen.with_timeout(timeout: Union[float, datetime.timedelta], future: Yieldable, quiet_exceptions: Union[Type[Exception], Tuple[Type[Exception], ...]] = ())[source]

Future(またはその他のyield可能なオブジェクト)をタイムアウトでラップします。

timeoutIOLoop.add_timeoutで許可される形式、つまりdatetime.timedeltaまたはIOLoop.timeを基準とした絶対時間)までに、入力futureが完了しない場合、tornado.util.TimeoutErrorを発生させます。

ラップされたFutureがタイムアウト後に失敗した場合、quiet_exceptions(例外型または型のシーケンス)に含まれる型であるか、asyncio.CancelledErrorでない限り、その例外はログに記録されます。

ラップされたFutureはタイムアウト時にキャンセルされません。そのため、再利用できます。asyncio.wait_forはこの関数に似ていますが、タイムアウト時にラップされたFutureをキャンセルします。

バージョン4.0の新機能。

バージョン4.1での変更: quiet_exceptions引数と未処理例外のログ記録が追加されました。

バージョン4.4での変更: Future以外のyield可能なオブジェクトのサポートが追加されました。

バージョン6.0.3での変更: asyncio.CancelledErrorは常に「静か」とみなされるようになりました。

バージョン6.2での変更: tornado.util.TimeoutErrorasyncio.TimeoutErrorのエイリアスになりました。

tornado.gen.sleep(duration: float) Future[None][source]

指定された秒数後に解決されるFutureを返します。

コルーチン内でyieldと共に使用する場合、これはtime.sleep(ブロッキングするため、コルーチンでは使用しないでください)のノンブロッキングなアナログです。

yield gen.sleep(0.5)

この関数を単独で呼び出しても何も行われません。返されたFutureを待機する必要があります(通常はyieldすることで)。

バージョン4.1の新機能。

class tornado.gen.WaitIterator(*args: Future, **kwargs: Future)[source]

awaitableの結果が完了する順にyieldするイテレータを提供します。

次のようなawaitableのセットをyieldする場合

results = yield [awaitable1, awaitable2]

awaitable1awaitable2の両方が返されるまでコルーチンを一時停止し、その後、両方のawaitableの結果を使用してコルーチンを再開します。いずれかのawaitableが例外を発生させると、その式はその例外を発生させ、すべての結果が失われます。

可能な限り早く各awaitableの結果を取得する必要がある場合、または他のawaitableがエラーを発生させても一部のawaitableの結果が必要な場合は、WaitIteratorを使用できます。

wait_iterator = gen.WaitIterator(awaitable1, awaitable2)
while not wait_iterator.done():
    try:
        result = yield wait_iterator.next()
    except Exception as e:
        print("Error {} from {}".format(e, wait_iterator.current_future))
    else:
        print("Result {} received from {} at {}".format(
            result, wait_iterator.current_future,
            wait_iterator.current_index))

結果は利用可能になり次第返されるため、イテレータからの出力は*入力引数と同じ順序ではありません*。現在の結果を生成したfutureを特定する必要がある場合は、属性WaitIterator.current_futureまたはWaitIterator.current_indexを使用して、入力リストからのawaitableのインデックスを取得します(WaitIteratorの構築時にキーワード引数が使用された場合、current_indexは対応するキーワードを使用します)。

Python 3.5では、WaitIteratorは非同期イテレータプロトコルを実装しているため、async forステートメントで使用できます(このバージョンでは、いずれかの値が例外を発生させると、反復全体が中止されますが、前の例では個々のエラーをスキップして続行できます)。

async for result in gen.WaitIterator(future1, future2):
    print("Result {} received from {} at {}".format(
        result, wait_iterator.current_future,
        wait_iterator.current_index))

バージョン4.1の新機能。

バージョン4.3での変更: Python 3.5でasync forサポートが追加されました。

done() bool[source]

このイテレータに結果がなくなった場合にTrueを返します。

next() Future[source]

次の利用可能な結果をyieldするFutureを返します。

このFutureは、入力のいずれかのオブジェクトと同じオブジェクトではありません。

tornado.gen.multi(Union[List[Yieldable], Dict[Any, Yieldable]], quiet_exceptions: Union[Type[Exception], Tuple[Type[Exception], ...]] = ())[source]

複数の非同期操作を並列に実行します。

childrenは、値がyield可能なオブジェクトであるリストまたは辞書です。multi()は、その結果を含む並列構造に解決される新しいyield可能なオブジェクトを返します。childrenがリストの場合、結果は同じ順序の結果のリストになります。辞書の場合、結果は同じキーを持つ辞書になります。

つまり、results = yield multi(list_of_futures)は次のものと同等です。

results = []
for future in list_of_futures:
    results.append(yield future)

いずれかのchildrenが例外を発生させると、multi()は最初の例外を発生させます。他のすべての例外は、quiet_exceptions引数に含まれる型でない限り、ログに記録されます。

yieldベースのcoroutineでは、リストまたは辞書がyieldされた際にcoroutine runnerが自動的に実行するため、通常この関数を直接呼び出す必要はありません。しかし、awaitベースのcoroutineの場合、またはquiet_exceptions引数を渡す必要がある場合は、この関数を呼び出す必要があります。

この関数は、歴史的な理由からmulti()Multi()という名前でも使用できます。

multi()によって返されるFutureをキャンセルしても、その子プロセスはキャンセルされません。asyncio.gathermulti()に似ていますが、子プロセスをキャンセルします。

バージョン4.2での変更: 複数のyieldableが失敗した場合、最初の例外(発生した例外)以降の例外はログに記録されます。選択した例外タイプのログを抑制するためのquiet_exceptions引数が追加されました。

バージョン4.3での変更: Multiクラスとmulti_future関数を、統一された関数multiに置き換えました。YieldPointFuture以外のyieldableのサポートを追加しました。

tornado.gen.multi_future(Union[List[Yieldable], Dict[Any, Yieldable]], quiet_exceptions: Union[Type[Exception], Tuple[Type[Exception], ...]] = ())[source]

複数の非同期Futureを並列に待ちます。

Tornado 6.0以降、この関数はmultiと全く同じです。

バージョン4.0の新機能。

バージョン4.2での変更: 複数のFuturesが失敗した場合、最初の例外(発生した例外)以降の例外はログに記録されます。選択した例外タイプのログを抑制するためのquiet_exceptions引数が追加されました。

バージョン4.3で非推奨: multiを使用してください。

tornado.gen.convert_yielded(yielded: Union[None, Awaitable, List[Awaitable], Dict[Any, Awaitable], Future]) Future[source]

yieldされたオブジェクトをFutureに変換します。

デフォルトの実装では、リスト、辞書、Futureを受け入れます。asyncio.ensure_futureと同様に、自身で開始されていないcoroutineをすべて開始するという副作用があります。

singledispatchライブラリが使用可能な場合、この関数を拡張して追加の型をサポートできます。例えば

@convert_yielded.register(asyncio.Future)
def _(asyncio_future):
    return tornado.platform.asyncio.to_tornado_future(asyncio_future)

バージョン4.1の新機能。

tornado.gen.maybe_future(x: Any) Future[source]

xFutureに変換します。

xが既にFutureである場合は、そのまま返されます。それ以外の場合は、新しいFutureでラップされます。これは、f()Futureを返すかどうかがわからない場合に、result = yield gen.maybe_future(f())として使用できます。

バージョン4.3で非推奨: この関数は、他のyieldableオブジェクトではなく、Futuresのみを処理します。maybe_futureの代わりに、期待する非Futureの結果型(多くの場合Noneのみ)を確認し、不明なものは何でもyieldしてください。

tornado.gen.is_coroutine_function(func: Any) bool[source]

funcがcoroutine関数であるか、つまりcoroutineでラップされた関数であるかどうかを返します。

バージョン4.5の新機能。

tornado.gen.moment

IOLoopを1回実行できるようにyieldできる特別なオブジェクトです。

通常の使用では必要ありませんが、すぐに準備できるFutureをyieldする可能性が高い、長時間実行されるcoroutineで役立つ場合があります。

使用方法: yield gen.moment

ネイティブcoroutineでは、yield gen.momentに相当するものはawait asyncio.sleep(0)です。

バージョン4.0の新機能。

バージョン4.5で非推奨: yield None(または引数なしのyield)は、現在yield gen.momentと同等です。