これはうまくいく方法ではありませんasyncio
。明示的な非同期モデルを使用します。コードが制御をイベント ループに戻す場合は、 を使用するかyield from
、 callbacks/ を使用する必要がありますFutures
。関数 ( など) の内部にいる場合は、 1) を使用して2) メソッドを完全に終了do_something_periodically
しないと、イベント ループに制御を戻すことはできません。クラスのおよび 非バージョンでyield from
ある程度のコードを再利用できますが、 を呼び出す必要があるメソッドは、それ自体も である必要があります。asyncio
asyncio
coroutine
coroutine
class MyClass(object):
def do_something_periodically(self, delay, repeats):
for i in range(repeats):
self.do_something_useful()
self._sleep(delay)
def _sleep(self, delay):
time.sleep(delay)
def do_something_useful(self):
# Do something useful here, which doesn't need to yield to the event loop
class MyAsyncioClass(MyClass):
@asyncio.coroutine
def do_something_periodically(self, delay, repeats):
for i in range(repeats):
self.do_something_useful()
yield from self._sleep(delay)
@asyncio.coroutine
def _sleep(self, delay):
yield from asyncio.sleep(delay)
そうは言っても、あなたの特定のユースケースは別の方法で解決できる可能性があるように見えますが、少し見苦しく、MyClass
ロジックを変更する必要があります。
class MyClass(object):
def do_something_periodically(self, delay, repeats, i=0):
while i < repeats:
# do something useful
if not self._sleep(delay, repeats, i):
break
i+= 1
return i
def _sleep(self, delay, repeats, i):
time.sleep(delay)
return True
class MyAsyncioClass(MyClass):
def do_something_periodically(self, delay, repeats, i=0):
out = super().do_something_periodically(delay, repeats, i)
if out == repeats:
asyncio.get_event_loop().stop()
def _sleep(self, delay, repeats, i):
i+=1
asyncio.get_event_loop().call_later(delay,
self.do_something_periodically,
delay, repeats, i)
return False
通常のユースケースのループを完全に反復するだけでなく、その場合に値を増やして繰り返し呼び出されることもサポートするために、 とloop.call_later
同等の操作を行います。asyncio.sleep
do_something_periodically
while
i
asyncio
asyncio
残念ながら、同期とユースケースの両方で同じコードを再利用する簡単で確実な方法はありません。asyncio
これは、 /のような明示的な非同期フレームワークと、暗黙の非同期モデルを使用する のtornado
ようなものの主な欠点の 1 つです。gevent
ではgevent
、が完了するまでイベント ループに制御を戻すバージョンtime.sleep(delay)
のパッチが適用されます。つまり、コードの変更は必要ありません。gevent
sleep