コンテキストの切り替えを防ぐために、ネットワーク接続といくつかのルーチンの両方を処理する大きなループを作成します。
通常の機能の実装は次のとおりです。
import asyncio
import time
def hello_world(loop):
print('Hello World')
loop.call_later(1, hello_world, loop)
def good_evening(loop):
print('Good Evening')
loop.call_later(1, good_evening, loop)
print('step: asyncio.get_event_loop()')
loop = asyncio.get_event_loop()
print('step: loop.call_soon(hello_world, loop)')
loop.call_soon(hello_world, loop)
print('step: loop.call_soon(good_evening, loop)')
loop.call_soon(good_evening, loop)
try:
# Blocking call interrupted by loop.stop()
print('step: loop.run_forever()')
loop.run_forever()
except KeyboardInterrupt:
pass
finally:
print('step: loop.close()')
loop.close()
コルーチンの実装は次のとおりです。
import asyncio
@asyncio.coroutine
def hello_world():
while True:
yield from asyncio.sleep(1)
print('Hello World')
@asyncio.coroutine
def good_evening():
while True:
yield from asyncio.sleep(1)
print('Good Evening')
print('step: asyncio.get_event_loop()')
loop = asyncio.get_event_loop()
try:
print('step: loop.run_until_complete()')
loop.run_until_complete(asyncio.wait([
hello_world(),
good_evening()
]))
except KeyboardInterrupt:
pass
finally:
print('step: loop.close()')
loop.close()
そして混合物:
import asyncio
import time
def hello_world(loop):
print('Hello World')
loop.call_later(1, hello_world, loop)
def good_evening(loop):
print('Good Evening')
loop.call_later(1, good_evening, loop)
@asyncio.coroutine
def hello_world_coroutine():
while True:
yield from asyncio.sleep(1)
print('Hello World Coroutine')
@asyncio.coroutine
def good_evening_coroutine():
while True:
yield from asyncio.sleep(1)
print('Good Evening Coroutine')
print('step: asyncio.get_event_loop()')
loop = asyncio.get_event_loop()
print('step: loop.call_soon(hello_world, loop)')
loop.call_soon(hello_world, loop)
print('step: loop.call_soon(good_evening, loop)')
loop.call_soon(good_evening, loop)
print('step: asyncio.async(hello_world_coroutine)')
asyncio.async(hello_world_coroutine())
print('step: asyncio.async(good_evening_coroutine)')
asyncio.async(good_evening_coroutine())
try:
loop.run_forever()
except KeyboardInterrupt:
pass
finally:
print('step: loop.close()')
loop.close()
ご覧のとおり、各コルーチン関数にはwhileループが囲まれています。どうすれば通常のようにできますか?つまり完了したら、指定された遅延時間の後に自分自身を呼び出しますが、ループを配置するだけではありません。
あなたが本当にコルーチンからwhileループを排除したい場合(なぜあなたはそれが必要だと思うのか分かりません;それはあなたがやろうとしていることを行うための最も自然な方法です)、あなたは _asyncio.async
_ (または_asyncio.ensure_future
_ on Python 3.4.4+)で、次のイベントループの反復でコルーチンを再度実行するようにスケジュールします。
_import asyncio
@asyncio.coroutine
def hello_world():
yield from asyncio.sleep(1)
print('Hello World')
asyncio.async(hello_world())
@asyncio.coroutine
def good_evening():
yield from asyncio.sleep(1)
print('Good Evening')
asyncio.async(good_evening())
print('step: asyncio.get_event_loop()')
loop = asyncio.get_event_loop()
try:
print('step: loop.run_until_complete()')
asyncio.async(hello_world())
asyncio.async(good_evening())
loop.run_forever()
except KeyboardInterrupt:
pass
finally:
print('step: loop.close()')
loop.close()
_
_hello_world
_/_good_evening
_は印刷後すぐに終了するため、これを行う場合はloop.run_forever()
を使用するように切り替える必要があることに注意してください。
# asyncio_coroutine_forever.py
import asyncio
async def hello_world():
await asyncio.sleep(1)
print('Hello World')
await good_evening()
async def good_evening():
await asyncio.sleep(1)
print('Good Evening')
await hello_world()
loop = asyncio.get_event_loop()
try:
loop.run_until_complete(hello_world())
loop.run_until_complete(good_evening())
loop.run_forever()
finally:
print('closing event loop')
loop.close()
import asyncio
@asyncio.coroutine
def hello_world_coroutine():
yield from asyncio.sleep(1)
print('Hello World Coroutine')
yield from hello_world_coroutine()
@asyncio.coroutine
def good_evening_coroutine():
yield from asyncio.sleep(1)
print('Good Evening Coroutine')
yield from good_evening_coroutine()
print('step: asyncio.get_event_loop()')
loop = asyncio.get_event_loop()
try:
print('step: loop.run_until_complete()')
loop.run_until_complete(asyncio.wait([
hello_world_coroutine(),
good_evening_coroutine()
]))
except KeyboardInterrupt:
pass
finally:
print('step: loop.close()')
loop.close()
[〜#〜] upd [〜#〜]
このコードは、最大再帰深度に達します。 Pythonにはテールコールの最適化がないため、ここのコードは間違った例として残してください。
あなたは実際にあなたが与えた3つの例を実行しようとしましたか?動作の違いは非常に明白です。
期待したことを言ったことがないので、何が正しいのか、何がそうでないのかを伝えることはありません。 3つの実装はすべて正しいか間違っている可能性があります。各実装にどのような動作があり、なぜそのような動作があるのかを説明できます。あなただけが正しいかどうかを知っています。
2番目の例(yield from asyncio.sleep(1)
)では、2つのコルーチンが同時に実行されます。これは、それぞれが独自に実行することを意味します。 hello_world
は毎秒Hello World
を出力し、good_evening
は毎秒Good Evening
を出力します。
他の2つの例は両方ともtime.sleep(1)
を使用していますが、これはブロッキングです。つまり、最初の関数(つまり、hello_world
)がtime.sleep(1)
に達すると、プログラム全体が1秒間ハングするになります。つまり、hello_world
がスリープすると、good_evening
も実行できず、その逆も同様です。
プログラムは次のように実行されます。
hello_world
を呼び出します。hello_world
のtime.sleep(1)
に達しました。プログラムは1秒間スリープします。Hello World
が印刷されました。hello_world
は降伏します。good_evening
を呼び出します。Good Evening
が印刷されました。good_evening
のtime.sleep(1)
に達しました。プログラムは1秒間スリープします。good_evening
は降伏します。したがって、Hello World
とGood Evening
は両方ともtwo秒ごとに表示されます。これは、各print
の間に2つのtime.sleep(1)
呼び出しがあるためです。 2つの例を実行すると、簡単にわかります。