イベントループ—Pythonドキュメント

提供:Dev Guides
< PythonPython/docs/3.8/library/asyncio-eventloop
移動先:案内検索

イベントループ

ソースコード: :source: `Lib / asyncio / events.py`, :source: `Lib / asyncio / base_events.py`



序文

イベントループは、すべてのasyncioアプリケーションの中核です。 イベントループは、非同期タスクとコールバックを実行し、ネットワークIO操作を実行し、サブプロセスを実行します。

アプリケーション開発者は通常、 asyncio.run()などの高レベルの非同期関数を使用する必要があり、ループオブジェクトを参照したりそのメソッドを呼び出したりする必要はほとんどありません。 このセクションは主に、イベントループの動作をより細かく制御する必要がある、低レベルのコード、ライブラリ、およびフレームワークの作成者を対象としています。

イベントループの取得

次の低レベル関数を使用して、イベントループを取得、設定、または作成できます。

asyncio.get_running_loop()

現在のOSスレッドで実行中のイベントループを返します。

実行中のイベントループがない場合、 RuntimeError が発生します。 この関数は、コルーチンまたはコールバックからのみ呼び出すことができます。

バージョン3.7の新機能。

asyncio.get_event_loop()

現在のイベントループを取得します。

現在のOSスレッドに現在のイベントループが設定されておらず、OSスレッドがメインであり、 set_event_loop()がまだ呼び出されていない場合、asyncioは新しいイベントループを作成し、それを現在のイベントループとして設定します。

この関数の動作はかなり複雑であるため(特にカスタムイベントループポリシーが使用されている場合)、コルーチンとコールバックでは get_event_loop()よりも get_running_loop()関数を使用することをお勧めします。

低レベルの関数を使用してイベントループを手動で作成および閉じる代わりに、 asyncio.run()関数を使用することも検討してください。

asyncio.set_event_loop(loop)
loop を現在のOSスレッドの現在のイベントループとして設定します。
asyncio.new_event_loop()
新しいイベントループオブジェクトを作成します。

get_event_loop()set_event_loop()、および new_event_loop()関数の動作は、カスタムイベントループポリシーを設定することで変更できることに注意してください[ X177X]。

コンテンツ

このドキュメントページには、次のセクションが含まれています。

イベントループメソッド

イベントループには、次の低レベル APIがあります。

ループの実行と停止

loop.run_until_complete(future)

futureFuture のインスタンス)が完了するまで実行します。

引数がコルーチンオブジェクトの場合、 asyncio.Task として実行するように暗黙的にスケジュールされます。

Futureの結果を返すか、その例外を発生させます。

loop.run_forever()

stop()が呼び出されるまで、イベントループを実行します。

run_forever()が呼び出される前に stop()が呼び出された場合、ループはタイムアウトゼロでI / Oセレクターを1回ポーリングし、I /に応答してスケジュールされたすべてのコールバックを実行します。 Oイベント(およびすでにスケジュールされているイベント)を実行して、終了します。

run_forever()の実行中に stop()が呼び出されると、ループは現在のコールバックのバッチを実行して終了します。 この場合、コールバックによってスケジュールされた新しいコールバックは実行されないことに注意してください。 代わりに、次に run_forever()または run_until_complete()が呼び出されたときに実行されます。

loop.stop()
イベントループを停止します。
loop.is_running()
イベントループが現在実行中の場合は、Trueを返します。
loop.is_closed()
イベントループが閉じられた場合は、Trueを返します。
loop.close()

イベントループを閉じます。

この関数を呼び出すときは、ループを実行してはなりません。 保留中のコールバックはすべて破棄されます。

このメソッドは、すべてのキューをクリアしてエグゼキュータをシャットダウンしますが、エグゼキュータが終了するのを待ちません。

この方法はべき等で不可逆的です。 イベントループが閉じられた後は、他のメソッドを呼び出さないでください。


コールバックのスケジュール

loop.call_soon(callback, *args, context=None)

callback callback が、イベントループの次の反復で args 引数を使用して呼び出されるようにスケジュールします。

コールバックは、登録された順序で呼び出されます。 各コールバックは1回だけ呼び出されます。

オプションのキーワードのみの context 引数を使用すると、コールバックを実行するカスタム contextvars.Context を指定できます。 現在のコンテキストは、 context が提供されていない場合に使用されます。

asyncio.Handle のインスタンスが返されます。これは、後でコールバックをキャンセルするために使用できます。

この方法はスレッドセーフではありません。

loop.call_soon_threadsafe(callback, *args, context=None)

call_soon()のスレッドセーフなバリアント。 別のスレッドからのコールバックをスケジュールするために使用する必要があります。

ドキュメントの同時実行およびマルチスレッドセクションを参照してください。

バージョン3.7で変更: context キーワードのみのパラメーターが追加されました。 詳細については、 PEP 567 を参照してください。


ノート

ほとんどの asyncio スケジューリング関数は、キーワード引数の受け渡しを許可していません。 これを行うには、 functools.partial()を使用します。

# will schedule "print("Hello", flush=True)"
loop.call_soon(
    functools.partial(print, "Hello", flush=True))

asyncioはデバッグメッセージやエラーメッセージで部分オブジェクトをより適切にレンダリングできるため、通常、部分オブジェクトを使用する方がラムダを使用するよりも便利です。


遅延コールバックのスケジュール

イベントループは、将来のある時点で呼び出されるコールバック関数をスケジュールするメカニズムを提供します。 イベントループは、単調なクロックを使用して時間を追跡します。

loop.call_later(delay, callback, *args, context=None)

指定された delay 秒数(intまたはfloatのいずれか)の後に呼び出されるように callback をスケジュールします。

asyncio.TimerHandle のインスタンスが返され、これを使用してコールバックをキャンセルできます。

コールバックは1回だけ呼び出されます。 2つのコールバックがまったく同じ時間にスケジュールされている場合、それらが呼び出される順序は定義されていません。

オプションの定位置 args は、呼び出されたときにコールバックに渡されます。 キーワード引数を使用してコールバックを呼び出す場合は、 functools.partial()を使用します。

オプションのキーワードのみの context 引数を使用すると、コールバックを実行するカスタム contextvars.Context を指定できます。 現在のコンテキストは、 context が提供されていない場合に使用されます。

バージョン3.7で変更: context キーワードのみのパラメーターが追加されました。 詳細については、 PEP 567 を参照してください。

バージョン3.8で変更:デフォルトのイベントループ実装を備えたPython 3.7以前では、 delay は1日を超えることはできませんでした。 これはPython3.8で修正されています。

loop.call_at(when, callback, *args, context=None)

loop.time()と同じ時間参照を使用して、コールバックが指定された絶対タイムスタンプ when (intまたはfloat)で呼び出されるようにスケジュールします。

このメソッドの動作は、 call_later()と同じです。

asyncio.TimerHandle のインスタンスが返され、これを使用してコールバックをキャンセルできます。

バージョン3.7で変更: context キーワードのみのパラメーターが追加されました。 詳細については、 PEP 567 を参照してください。

バージョン3.8で変更:デフォルトのイベントループ実装を備えたPython 3.7以前では、 when と現在の時刻の差は1日を超えることはできませんでした。 これはPython3.8で修正されています。

loop.time()
イベントループの内部単調クロックに従って、現在の時刻を float 値として返します。

ノート

バージョン3.8で変更: Python 3.7以前では、タイムアウト(相対遅延または絶対の場合)は1日を超えてはなりません。 これはPython3.8で修正されています。


も参照してください

asyncio.sleep()機能。


先物とタスクの作成

loop.create_future()

イベントループにアタッチされた asyncio.Future オブジェクトを作成します。

これは、asyncioでFuturesを作成するための推奨される方法です。 これにより、サードパーティのイベントループがFutureオブジェクトの代替実装を提供できるようになります(パフォーマンスまたはインストルメンテーションが向上します)。

バージョン3.5.2の新機能。

loop.create_task(coro, *, name=None)

コルーチンの実行をスケジュールします。 Task オブジェクトを返します。

サードパーティのイベントループは、相互運用性のために Task の独自のサブクラスを使用できます。 この場合、結果タイプは Task のサブクラスです。

name 引数がNoneではなく指定されている場合、 Task.set_name()を使用してタスクの名前として設定されます。

バージョン3.8で変更: nameパラメーターが追加されました。

loop.set_task_factory(factory)

loop.create_task()で使用されるタスクファクトリを設定します。

factoryNoneの場合、デフォルトのタスクファクトリが設定されます。 それ以外の場合、 factory は、(loop, coro)と一致する署名を持つ callable である必要があります。ここで、 loop はアクティブなイベントループへの参照であり、[X160X ] coro はコルーチンオブジェクトです。 呼び出し可能オブジェクトは、 asyncio.Future 互換オブジェクトを返す必要があります。

loop.get_task_factory()
タスクファクトリを返すか、デフォルトのものが使用されている場合はNoneを返します。


ネットワーク接続を開く

ネットワークサーバーの作成

ファイルの転送

TLSアップグレード

ファイル記述子の監視

loop.add_reader(fd, callback, *args)
fd ファイル記述子の読み取り可能性の監視を開始し、 fd が読み取り可能になったら、指定された引数を使用してコールバックを呼び出します。
loop.remove_reader(fd)
fd ファイル記述子の読み取りの可用性の監視を停止します。
loop.add_writer(fd, callback, *args)

fd ファイル記述子の書き込み可能性の監視を開始し、 fd が書き込み可能になったら、指定された引数を使用してコールバックを呼び出します。

functools.partial() を使用して、キーワード引数コールバックに渡します。

loop.remove_writer(fd)
fd ファイル記述子の書き込み可能性の監視を停止します。

これらのメソッドのいくつかの制限については、プラットフォームサポートセクションも参照してください。


ソケットオブジェクトを直接操作する

一般に、loop.create_connection()loop.create_server()などのトランスポートベースのAPIを使用するプロトコルの実装は、ソケットを直接操作する実装よりも高速です。 ただし、パフォーマンスが重要ではないユースケースがいくつかあり、 socket オブジェクトを直接操作する方が便利です。


DNS

バージョン3.7で変更: getaddrinfo メソッドと getnameinfo メソッドの両方が常にコルーチンを返すように文書化されていましたが、Python 3.7より前は、実際には[X192X ] asyncio.Future オブジェクト。 Python 3.7以降、どちらの方法もコルーチンです。


パイプの操作

ノート

SelectorEventLoop は、Windowsで上記のメソッドをサポートしていません。 Windowsの代わりに ProactorEventLoop を使用してください。


も参照してください

loop.subprocess_exec()およびloop.subprocess_shell()メソッド。


Unixシグナル

loop.add_signal_handler(signum, callback, *args)

callbacksignum 信号のハンドラーとして設定します。

コールバックは、 loop によって、他のキューに入れられたコールバックおよびそのイベントループの実行可能なコルーチンとともに呼び出されます。 signal.signal()を使用して登録されたシグナルハンドラーとは異なり、この関数に登録されたコールバックは、イベントループと対話できます。

シグナル番号が無効またはキャッチできない場合は、 ValueError を発生させます。 ハンドラーの設定に問題がある場合は、 RuntimeError を発生させます。

functools.partial() を使用して、キーワード引数コールバックに渡します。

signal.signal()と同様に、この関数はメインスレッドで呼び出す必要があります。

loop.remove_signal_handler(sig)

sig 信号のハンドラーを削除します。

シグナルハンドラーが削除された場合はTrueを返し、指定されたシグナルにハンドラーが設定されていない場合はFalseを返します。

も参照してください

信号モジュール。


スレッドまたはプロセスプールでコードを実行する

loop.set_default_executor(executor)

executor を、run_in_executor()が使用するデフォルトのエグゼキュータとして設定します。 executer は、 ThreadPoolExecutor のインスタンスである必要があります。

バージョン3.8以降非推奨: ThreadPoolExecutor のインスタンスではないエグゼキューターの使用は非推奨になり、Python3.9でエラーがトリガーされます。

executer は、 concurrent.futures.ThreadPoolExecutor のインスタンスである必要があります。


エラー処理API

イベントループでの例外の処理方法をカスタマイズできます。

loop.set_exception_handler(handler)

handler を新しいイベントループ例外ハンドラーとして設定します。

handlerNoneの場合、デフォルトの例外ハンドラーが設定されます。 それ以外の場合、ハンドラーは、(loop, context)と一致する署名を持つ呼び出し可能である必要があります。ここで、loopはアクティブなイベントループへの参照であり、contextは[例外の詳細を含むX162X] オブジェクト(コンテキストの詳細については、 call_exception_handler()のドキュメントを参照してください)。

loop.get_exception_handler()

現在の例外ハンドラーを返します。カスタム例外ハンドラーが設定されていない場合はNoneを返します。

バージョン3.5.2の新機能。

loop.default_exception_handler(context)

デフォルトの例外ハンドラ。

これは、例外が発生し、例外ハンドラーが設定されていない場合に呼び出されます。 これは、デフォルトのハンドラーの動作を延期したいカスタム例外ハンドラーによって呼び出すことができます。

context パラメーターは、 call_exception_handler()と同じ意味です。

loop.call_exception_handler(context)

現在のイベントループ例外ハンドラーを呼び出します。

context は、次のキーを含むdictオブジェクトです(新しいキーは将来のPythonバージョンで導入される可能性があります)。

  • 'メッセージ':エラーメッセージ;

  • 'exception'(オプション):例外オブジェクト。

  • 'future'(オプション): asyncio.Future インスタンス;

  • 'handle'(オプション): asyncio.Handle インスタンス;

  • 'protocol'(オプション): Protocol インスタンス;

  • 'transport'(オプション): Transport インスタンス;

  • 'socket'(オプション): socket.socket インスタンス。

ノート

このメソッドは、サブクラス化されたイベントループでオーバーロードしないでください。 カスタム例外処理には、 set_exception_handler()メソッドを使用します。


デバッグモードの有効化

loop.get_debug()

イベントループのデバッグモード( bool )を取得します。

環境変数 PYTHONASYNCIODEBUG が空でない文字列に設定されている場合、デフォルト値はTrueであり、それ以外の場合はFalseです。

loop.set_debug(enabled: bool)

イベントループのデバッグモードを設定します。

バージョン3.7で変更:新しい-X devコマンドラインオプションを使用して、デバッグモードを有効にすることもできるようになりました。

も参照してください

asyncio デバッグモード。


サブプロセスの実行

このサブセクションで説明する方法は低レベルです。 通常のasync / awaitコードでは、代わりに高レベルのasyncio.create_subprocess_shell()およびasyncio.create_subprocess_exec()コンビニエンス関数の使用を検討してください。

ノート

Windows のデフォルトのasyncioイベントループはサブプロセスをサポートしていません。 詳細については、 Windowsでのサブプロセスサポートを参照してください。


ノート

シェルインジェクションの脆弱性を回避するために、すべての空白文字と特殊文字が適切に引用されていることを確認するのはアプリケーションの責任です。 shlex.quote()関数を使用すると、シェルコマンドの作成に使用される文字列内の空白や特殊文字を適切にエスケープできます。


コールバックハンドル

class asyncio.Handle

loop.call_soon()loop.call_soon_threadsafe()によって返されるコールバックラッパーオブジェクト。

cancel()

コールバックをキャンセルします。 コールバックがすでにキャンセルまたは実行されている場合、このメソッドは効果がありません。

cancelled()

コールバックがキャンセルされた場合は、Trueを返します。

バージョン3.7の新機能。

class asyncio.TimerHandle

loop.call_later()および loop.call_at()によって返されるコールバックラッパーオブジェクト。

このクラスは、 Handle のサブクラスです。

when()

スケジュールされたコールバック時間を float 秒として返します。

時間は絶対タイムスタンプであり、 loop.time()と同じ時間参照を使用します。

バージョン3.7の新機能。


サーバーオブジェクト

サーバーオブジェクトは、loop.create_server()loop.create_unix_server()start_server()、およびstart_unix_server()関数によって作成されます。

クラスを直接インスタンス化しないでください。

class asyncio.Server

Server オブジェクトは非同期コンテキストマネージャーです。 async withステートメントで使用すると、async withステートメントが完了すると、サーバーオブジェクトが閉じられ、新しい接続を受け入れないことが保証されます。

srv = await loop.create_server(...)

async with srv:
    # some code

# At this point, srv is closed and no longer accepts new connections.

バージョン3.7で変更:サーバーオブジェクトはPython3.7以降の非同期コンテキストマネージャーです。

close()

提供を停止する:リスニングソケットを閉じ、 sockets 属性をNoneに設定します。

既存の着信クライアント接続を表すソケットは開いたままになります。

サーバーは非同期で閉じられます。wait_closed()コルーチンを使用して、サーバーが閉じられるまで待機します。

get_loop()

サーバーオブジェクトに関連付けられたイベントループを返します。

バージョン3.7の新機能。

is_serving()

サーバーが新しい接続を受け入れている場合は、Trueを返します。

バージョン3.7の新機能。

sockets

サーバーがリッスンしている socket.socket オブジェクトのリスト。

バージョン3.7で変更: Python3.7より前Server.socketsは、サーバーソケットの内部リストを直接返すために使用されていました。 3.7では、そのリストのコピーが返されます。


イベントループの実装

asyncioには、 SelectorEventLoopProactorEventLoop の2つの異なるイベントループ実装が付属しています。

デフォルトでは、asyncioはUnixでは SelectorEventLoop を使用し、Windowsでは ProactorEventLoop を使用するように構成されています。

class asyncio.SelectorEventLoop

セレクターモジュールに基づくイベントループ。

特定のプラットフォームで利用可能な最も効率的なセレクターを使用します。 使用する正確なセレクター実装を手動で構成することもできます。

import asyncio
import selectors

selector = selectors.SelectSelector()
loop = asyncio.SelectorEventLoop(selector)
asyncio.set_event_loop(loop)
class asyncio.ProactorEventLoop

「I / O完了ポート」(IOCP)を使用するWindowsのイベントループ。

class asyncio.AbstractEventLoop

非同期準拠のイベントループの抽象基本クラス。

イベントループメソッドセクションには、AbstractEventLoopの代替実装で定義する必要のあるすべてのメソッドが一覧表示されます。


このセクションのすべての例意図的には、 loop.run_forever()loop.call_soon()などの低レベルのイベントループAPIの使用方法を示していることに注意してください。 ]。 最新の非同期アプリケーションをこのように作成する必要はめったにありません。 asyncio.run()のような高レベルの関数の使用を検討してください。

call_soon()を使用したHello World

loop.call_soon()メソッドを使用してコールバックをスケジュールする例。 コールバックは"Hello World"を表示してから、イベントループを停止します。

import asyncio

def hello_world(loop):
    """A callback to print 'Hello World' and stop the event loop"""
    print('Hello World')
    loop.stop()

loop = asyncio.get_event_loop()

# Schedule a call to hello_world()
loop.call_soon(hello_world, loop)

# Blocking call interrupted by loop.stop()
try:
    loop.run_forever()
finally:
    loop.close()

も参照してください

コルーチンと run()関数を使用して作成された同様の Hello World の例。


call_later()で現在の日付を表示する

現在の日付を毎秒表示するコールバックの例。 コールバックは、 loop.call_later()メソッドを使用して、5秒後に自身を再スケジュールし、イベントループを停止します。

import asyncio
import datetime

def display_date(end_time, loop):
    print(datetime.datetime.now())
    if (loop.time() + 1.0) < end_time:
        loop.call_later(1, display_date, end_time, loop)
    else:
        loop.stop()

loop = asyncio.get_event_loop()

# Schedule the first call to display_date()
end_time = loop.time() + 5.0
loop.call_soon(display_date, end_time, loop)

# Blocking call interrupted by loop.stop()
try:
    loop.run_forever()
finally:
    loop.close()

も参照してください

コルーチンと run()関数を使用して作成された同様の現在の日付の例。


読み取りイベントのファイル記述子を監視する

loop.add_reader()メソッドを使用してファイル記述子がデータを受信するまで待ってから、イベントループを閉じます。

import asyncio
from socket import socketpair

# Create a pair of connected file descriptors
rsock, wsock = socketpair()

loop = asyncio.get_event_loop()

def reader():
    data = rsock.recv(100)
    print("Received:", data.decode())

    # We are done: unregister the file descriptor
    loop.remove_reader(rsock)

    # Stop the event loop
    loop.stop()

# Register the file descriptor for read event
loop.add_reader(rsock, reader)

# Simulate the reception of data from the network
loop.call_soon(wsock.send, 'abc'.encode())

try:
    # Run the event loop
    loop.run_forever()
finally:
    # We are done. Close sockets and the event loop.
    rsock.close()
    wsock.close()
    loop.close()

も参照してください

  • トランスポート、プロトコル、およびloop.create_connection()メソッドを使用した同様の
  • 高レベルのasyncio.open_connection()関数とストリームを使用した別の同様の


SIGINTおよびSIGTERMのシグナルハンドラーを設定します

(このsignalsの例はUnixでのみ機能します。)

loop.add_signal_handler()メソッドを使用して、シグナルSIGINTおよびSIGTERMのハンドラーを登録します。

import asyncio
import functools
import os
import signal

def ask_exit(signame, loop):
    print("got signal %s: exit" % signame)
    loop.stop()

async def main():
    loop = asyncio.get_running_loop()

    for signame in {'SIGINT', 'SIGTERM'}:
        loop.add_signal_handler(
            getattr(signal, signame),
            functools.partial(ask_exit, signame, loop))

    await asyncio.sleep(3600)

print("Event loop running for 1 hour, press Ctrl+C to interrupt.")
print(f"pid {os.getpid()}: send SIGINT or SIGTERM to exit.")

asyncio.run(main())