2015-03-15 17 views
6

मुझे अपने सिर को लपेटने में परेशानी हो रही है कि कैसे coroutines एक साथ बंधे हैं।एसिन्सीओ (और पर्यवेक्षक पैटर्न) में चेनिंग कोरआउटिन

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

मैं इस उम्मीद करेंगे: हैलो दुनिया या factorials की तुलना में एक थोड़ा कम तुच्छ उदाहरण में, मैं एक पाश जो लगातार फ़ाइल संशोधन बार देखता है, और फिर समय जब भी फ़ाइल को छुआ है बाहर प्रिंट करना चाहते हैं काम करने के लिए - हालांकि, जब मैं इसे चलाता हूं तो मुझे एक मिलता है:

RuntimeError: Task got bad yield: 1426449327.2590399 

मैं यहां क्या गलत कर रहा हूं?

अपडेट: पर्यवेक्षक पैटर्न के उदाहरण के लिए नीचे मेरा उत्तर देखें (यानी कॉलबैक का उपयोग किए बिना एकाधिक रजिस्ट्रारों को अद्यतन प्राप्त करने की अनुमति दें) (आपको कार्य का उपयोग करना होगा)।

UPDATE2: 3.5 के async for (अतुल्यकालिक iterators): https://www.python.org/dev/peps/pep-0492/

उत्तर

4

मैं return बजाय yield का उपयोग कर श्रृंखलित coroutine में से काम कर अपने कोड मिल गया, बस chained coroutines 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() 

ध्यान दें कि printer() के पाश प्रत्येक यात्रा के लिए एक नया pathmonitor जनरेटर का निर्माण करेगा। निश्चित नहीं है कि यह आपके मन में था लेकिन यह एक शुरुआत हो सकती है।

मुझे कोरआउट एपीआई और वाक्यविन्यास थोड़ा उलझन में मिलता है। यहाँ कुछ पढ़ने कि मैं उपयोगी पाया है है:

+1

उपयोगी जवाब- के लिए धन्यवाद: मेरे pathmonitor कुछ इस तरह लग रहा है। मुझे आश्चर्य है कि क्यों कोरआउट एक सामान्य जनरेटर की तरह उपज का उपयोग करने में सक्षम नहीं हैं। – gnr

+0

हाँ, यह उत्सुक है। आप नियमित रूप से जनरेटर के रूप में 'पथमापक' को फिर से लिख सकते हैं और नींद को 'प्रिंटर' पर ले जा सकते हैं। लेकिन मुझे लगता है कि आप एक जंजीर coroutine चाहता था। –

+1

आह यह एक दिलचस्प विचार है - मैं यह देखने के लिए थोड़ा सा खेलूँगा कि मैं किसके साथ आ सकता हूं। मेरे पास लाइब्रेरी कोड है जो फ़ाइल को छूने पर सूचित करने के लिए कॉलबैक का उपयोग करता है और मैं देखना चाहता हूं कि इसे कोरआउट (या बिना कॉलबैक के) के साथ कैसे काम करना है। मेरे पास एक प्रिंटर फ़ंक्शन, या लॉगर फ़ंक्शन, या सॉकेट फ़ंक्शन होगा जो फ़ाइल को स्पर्श होने पर कुछ अलग तरीके से कर सकता है। – gnr

0

के रूप में अन्य लोगों ने बताया, मेरी गलती थी कि मैं एक coroutine उपयोग करने के लिए कोशिश कर रहा था जनरेटर की तरह। पुनरावृत्ति के लिए जनरेटर पर भरोसा करने के बजाय, मुझे एकाधिक कोरआउट बनाने की आवश्यकता थी। इसके अलावा, मुझे कॉलबैक के बिना पर्यवेक्षक पैटर्न को लागू करने के लिए कार्यों का उपयोग करने की आवश्यकता थी क्योंकि एकाधिक रजिस्ट्रार yield from एक ही कार्य कर सकते हैं। एक सरल उपज अनुमति नहीं है - डॉक्स को देखकर थोड़ा अधिक मैंने देखा है वे बताती हैं कि एक coroutine केवल वापसी या से उपज कर सकते हैं के बाद

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() 
संबंधित मुद्दे