2015-03-15 23 views
6

Kafamı, birlikte zincirleme zincirleri etrafında sarmakla ilgili sorun yaşıyorum.asyncio (ve gözlemci deseninde) zincirleme koroutinleri

#!/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() 

bu beklenir: merhaba dünya ya faktöriyellerin göre biraz daha az önemsiz örnekte, sürekli dosya değişiklik zamanları izler ve ardından dosya değdiği anda zaman aşımına yazdıran bir döngü var istiyorum Çalışır - ancak, çalıştırdığımda, şunu alırım:

RuntimeError: Task got bad yield: 1426449327.2590399 
Burada yanlış olan ne yapıyorum?

GÜNCELLEME: geri aramaları kullanmadan (Görevler kullanmanız gerekir) gözlemci kalıbı örneği için (örneğin, bir dosyaya dokunduğunda birden çok kayıt aracının bir dosyaya dokunulduğunda güncelleştirmelerin verimli bir şekilde izin vermesine izin vermek için) aşağıdaki cevabıma bakın.

Update2: sadece chained coroutines example gibi https://www.python.org/dev/peps/pep-0492/

cevap

4

ben zincirlenmiş eşyordamın içinde return kullanılarak yerine yield tarafından çalışma kodunuzu var: 3.5 en async for (asenkron yineleyiciler): Bunun için daha iyi bir düzeltme var

printer() 'ın döngü her yineleme için yeni pathmonitor jeneratör yaratacak
#!/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() 

Not. Aklında olan şey bu olduğundan emin değil ama bir başlangıç ​​olabilir.

Ben coroutines API ve sözdizimini biraz kafa karıştırıcı buluyorum. İşte yararlı bulduk bazı kaynaklar verilmiştir:

+1

Teşekkür biraz daha onlar bir eşyordam sadece iade veya gelen verim açık bir biçimde ifade fark dokümanlar baktıktan sonra - Basit bir verim izin verilmez. Neden koroutinlerin normal bir jeneratör gibi verimi kullanamadıklarını merak ediyorum. – gnr

+0

Evet, meraklı. 'Rota izleyicisini' normal bir jeneratör olarak yeniden yazabilir ve uykuyı 'yazıcıya taşıyabilirsiniz. Ama sanırım zincirli bir koroutin istedin. –

+1

Ah ilginç bir fikir - Ne bulabileceğimi görmek için biraz oynarım. Bir dosyaya ne zaman dokunduğumu bildirmek için geri aramaları kullanan kütüphane kodum var ve bunu (veya geri aramalar olmadan) koroutinler ile nasıl çalıştırılacağını görmek istiyorum. Dosyaya dokunduğunda, farklı bir şey yapabilecek bir yazıcı işlevi veya bir kayıt fonksiyonu veya bir soket işlevi olurdu. – gnr

0

diğerleri belirttiği gibi, benim hatam ben eşyordam kullanmaya çalışıyordu ki bir jeneratör gibi. Yineleme için bir jeneratörü kullanmak yerine, çoklu koroutinler oluşturmam gerekiyordu. Ayrıca, birden fazla tescil ettirenin aynı görev için yield from yapabildiğinden, gözlemci şablonunu geri aramalar olmadan uygulamak için görevleri kullanmam gerekiyordu. Benim pathmonitor şöyle görünür: yararlı cevaplayan için

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()