Asyncio chain coroutines (and observer pattern)

I am having problems wrapping my head around how coroutines are connected together. In a slightly less trivial example than hello world or factorials, I would like to have a loop that constantly monitors the time the file changed and then prints the time when the file is affected:

#!/usr/bin/env python3 import os import asyncio @asyncio.coroutine def pathmonitor(path): modtime = os.path.getmtime(path) while True: new_time = os.path.getmtime(path) if new_time != modtime: modtime = new_time yield modtime yield from asyncio.sleep(1) @asyncio.coroutine def printer(): while True: modtime = yield from pathmonitor('/home/users/gnr/tempfile') print(modtime) loop = asyncio.get_event_loop() loop.run_until_complete(printer()) loop.run_forever() 

I expect this to work - however, when I run it, I get:

 RuntimeError: Task got bad yield: 1426449327.2590399 

What am I doing wrong here?

UPDATE: see my answer below for an example of an observer pattern (i.e. effectively allowing multiple registrars to receive updates when a file is touched) without using callbacks (you should use Tasks).

UPDATE2: there is a better fix for this: 3.5 async for (asynchronous iterators): https://www.python.org/dev/peps/pep-0492/

+6
source share
2 answers

I got your code using return instead of yield in the coroutine chain, just like a chained accompanying example :

 #!/usr/bin/env python3 import os import asyncio2 @asyncio.coroutine def pathmonitor(path): modtime = os.path.getmtime(path) while True: new_time = os.path.getmtime(path) if new_time != modtime: modtime = new_time return modtime yield from asyncio.sleep(1) @asyncio.coroutine def printer(): while True: modtime = yield from pathmonitor('/tmp/foo.txt') print(modtime) loop = asyncio.get_event_loop() loop.run_until_complete(printer()) loop.run_forever() 

Note that the printer() loop will create a new pathmonitor generator for each iteration. Not sure if this is what you had in mind, but this may be the beginning.

I find the API and coroutines syntax a little confusing myself. Here are some readings I found useful:

+4
source

As others pointed out, my mistake was that I was trying to use a coroutine as a generator. Instead of relying on the generator for iteration, I needed to create several coroutines. In addition, I needed to use tasks to implement the observer pattern without callbacks, since multiple registrants can yield from perform the same task. My road monitor looks something like this:

 import os import asyncio class PathInfo: def __init__(self, path): self.path = path self.modtime = os.path.getmtime(path) self.startTask() def startTask(self): self.task = asyncio.async(self._checkIfTouched()) def _checkIfTouched(self): while True: yield from asyncio.sleep(1) newtime = os.path.getmtime(self.path) if self.modtime != newtime: self.modtime = newtime return newtime class PathMonitor: def __init__(self): self._info = {} @asyncio.coroutine def wasTouched(self, path): try: info = self._info[path] except KeyError: self._info[path] = info = PathInfo(path) if info.task.done(): info.startTask() modtime = yield from info.task return modtime def printer(): while True: modtime = yield from mon.wasTouched('/tmp/myfile') print(modtime) mon = PathMonitor() loop = asyncio.get_event_loop() asyncio.async(printer()) loop.run_forever() 
0
source

Source: https://habr.com/ru/post/983832/


All Articles