2015-11-30 13 views
8

私は、call_laterを使用してPython 3.4のasyncioで作られた簡単なコードコードを持っています。コードは10秒間待機し、印刷してから、再度印刷する必要があります(その代わり、end()がexcecutedしなければならないときTypeError上げ、下記を参照してください):どのような私ができることからasyncioのcall_laterは、コルーチンオブジェクトで呼び出すことができません

Exception in callback <generator object coro at 0x7fc88eeaddc8>() 
handle: <TimerHandle when=31677.188005054 <generator object coro at 0x7fc88eeaddc8>()> 
Traceback (most recent call last): 
    File "/usr/lib64/python3.4/asyncio/events.py", line 119, in _run 
    self._callback(*self._args) 
TypeError: 'generator' object is not callable 

import asyncio 

@asyncio.coroutine 
def begin(): 
    print("Starting to wait.") 
    asyncio.get_event_loop().call_later(10, end()) 

@asyncio.coroutine 
def end(): 
    print("completed") 

if __name__ == "__main__": 
    try: 
     loop = asyncio.get_event_loop() 
     loop.create_task(begin()) 
     loop.run_forever() 
    except KeyboardInterrupt: 
     print("Goodbye!") 

はエラーになりますドキュメント(https://docs.python.org/3/library/asyncio-task.html#coroutine)から、call_laterはコルーチン関数を呼び出すことによって得られるコルーチンオブジェクトを受け取ります。これは私がやったようだが、asyncioはend()を正しく呼んでいない。

どうすればいいですか?

答えて

7

call_laterは、コルーチンではなくコールバック(通常の関数オブジェクトを意味する)をとるように設計されています。新しいバージョンのPythonでは、実際に明示的にこれを言うだろう:

import asyncio 

@asyncio.coroutine 
def begin(): 
    print("Starting to wait.") 
    asyncio.get_event_loop().call_later(10, end) 

def end(): 
    print("completed") 

if __name__ == "__main__": 
    try: 
     loop = asyncio.get_event_loop() 
     loop.create_task(begin()) 
     loop.run_forever() 
    except KeyboardInterrupt: 
     print("Goodbye!") 

出力:

Starting to wait. 
Task exception was never retrieved 
future: <Task finished coro=<coro() done, defined at /usr/lib/python3.4/asyncio/coroutines.py:139> exception=TypeError('coroutines cannot be used with call_at()',)> 
Traceback (most recent call last): 
    File "/usr/lib/python3.4/asyncio/tasks.py", line 238, in _step 
    result = next(coro) 
    File "/usr/lib/python3.4/asyncio/coroutines.py", line 141, in coro 
    res = func(*args, **kw) 
    File "aio.py", line 6, in begin 
    asyncio.get_event_loop().call_later(10, end()) 
    File "/usr/lib/python3.4/asyncio/base_events.py", line 392, in call_later 
    timer = self.call_at(self.time() + delay, callback, *args) 
    File "/usr/lib/python3.4/asyncio/base_events.py", line 404, in call_at 
    raise TypeError("coroutines cannot be used with call_at()") 
TypeError: coroutines cannot be used with call_at() 

はあなたがcall_laterに渡す通常の関数を、である必要がendあなたのコードの作品を​​、作るために

Starting to wait. 
completed 
Goodbye! 

endがコルーチンである必要がある場合、遅れてそれを呼び出すより自然な方法は、を使用することです:

import asyncio 

@asyncio.coroutine 
def begin(): 
    print("Starting to wait.") 
    yield from asyncio.sleep(10) 
    yield from end() 

@asyncio.coroutine 
def end(): 
    print("completed") 

if __name__ == "__main__": 
    try: 
     loop = asyncio.get_event_loop() 
     loop.create_task(begin()) 
     loop.run_forever() 
    except KeyboardInterrupt: 
     print("Goodbye!") 

技術が、これは動作しません:その場合は

asyncio.get_event_loop().call_later(10, lambda: asyncio.async(end())) 
+1

、後で 'asyncio'と呼ばれるコルーチンをスケジュールする方法はありますか?または、これが意味をなさない理由がいくつかありますか? –

+3

@ NathanaelFarleyさて、あなたは 'call_later(10、lambda:asyncio.ensure_future(end()))'を使うことができます。しかし 'asyncio.sleep(10)'からのyieldを 'begin'の中に入れ、その直後に' yield from end() 'を呼び出すほうが意味があります。 'begin'をブロックしたくない場合は、' asyncio.sleep'を入れて別のコルーチンに 'end'を呼ぶだけで、' begin'の中に 'asyncio.ensure_future(other_coroutine())'を呼び出すことができます。 – dano

関連する問題