2014-04-07 9 views
8

के साथ सरल एसिंक उदाहरण मैं सरल async सर्वर उदाहरण ढूंढना चाहता हूं। मैं इंतजार की बहुत, डेटाबेस लेनदेन ... आदि के साथ कुछ समारोह मिल गया है: मैं इसे रोके बिना अलग प्रक्रिया में समारोह को चलाने की जरूरत हैटॉरनाडो पायथन

def blocking_task(n): 
    for i in xrange(n): 
     print i 
     sleep(1) 
    return i 

। क्या यह संभव है?

उत्तर

16

टोरनाडो को आपके सभी परिचालनों को एक थ्रेड में चलाने के लिए डिज़ाइन किया गया है, लेकिन जितना संभव हो सके अवरुद्ध करने से बचने के लिए एसिंक्रोनस I/O का उपयोग करें। यदि आपके द्वारा उपयोग किए जाने वाले डीबी में एक्रोन्रोनस पायथन बाइंडिंग्स हैं (आदर्श रूप से टोरनाडो के लिए तैयार किए गए हैं, जैसे कि Motor मोंगोडीबी के लिए या momoko पोस्टग्रेज़ के लिए), तो आप सर्वर को अवरुद्ध किए बिना अपने डीबी प्रश्नों को चलाने में सक्षम होंगे; कोई अलग प्रक्रिया या धागे की जरूरत नहीं है।

सटीक उदाहरण दिया था, जहां time.sleep(1) कहा जाता है के लिए, आप बवंडर coroutines के माध्यम से एसिंक्रोनस यह करने के लिए इस दृष्टिकोण का उपयोग कर सकते हैं:

#!/usr/bin/python 

import tornado.web 
from tornado.ioloop import IOLoop 
from tornado import gen 
import time 

@gen.coroutine 
def async_sleep(seconds): 
    yield gen.Task(IOLoop.instance().add_timeout, time.time() + seconds) 

class TestHandler(tornado.web.RequestHandler): 
    @gen.coroutine 
    def get(self): 
     for i in xrange(100): 
      print i 
      yield async_sleep(1) 
     self.write(str(i)) 
     self.finish() 


application = tornado.web.Application([ 
    (r"/test", TestHandler), 
    ]) 

application.listen(9999) 
IOLoop.instance().start() 

दिलचस्प हिस्सा async_sleep है। वह विधि एक एसिंक्रोनस टास्क बना रही है, जो ioloop.add_timeout विधि को कॉल कर रही है। add_timeout टाइमआउट के समाप्त होने की प्रतीक्षा करते समय ioloop को अवरुद्ध किए बिना, दिए गए सेकंड के बाद निर्दिष्ट कॉलबैक चलाएगा।

add_timeout(deadline, callback) # deadline is the number of seconds to wait, callback is the method to call after deadline. 

आप ऊपर के उदाहरण में देख सकते हैं, हम केवल वास्तव में एक पैरामीटर add_timeout को स्पष्ट रूप से कोड में प्रदान कर रहे हैं, जिसका अर्थ है कि हम अंत में यह इस:

add_timeout(time.time() + seconds, ???) 
यह दो तर्क की उम्मीद

हम अपेक्षित कॉलबैक पैरामीटर प्रदान नहीं कर रहे हैं। वास्तव में, जब gen.Taskadd_timeout निष्पादित करता है, तो यह स्पष्ट रूप से प्रदान किए गए पैरामीटर के अंत में callback कीवर्ड तर्क जोड़ता है। तो यह:

yield gen.Task(loop.add_timeout, time.time() + seconds) 

परिणाम इस में gen.Task() के अंदर निष्पादित किया जा रहा:

loop.add_timeout(time.time() + seconds, callback=gen.Callback(some_unique_key)) 

gen.Callback टाइमआउट के बाद मार डाला है, यह संकेत है gen.Task पूरा हो गया है कि, और प्रोग्राम निष्पादन होगा अगली पंक्ति पर जारी रखें। यह प्रवाह पूरी तरह से समझने में मुश्किल है, कम से कम पहले (यह निश्चित रूप से मेरे लिए था जब मैंने इसे पहले पढ़ा था)। यह शायद Tornado gen module documentation पर कुछ बार पढ़ने में मददगार होगा।

4
import tornado.web 
from tornado.ioloop import IOLoop 
from tornado import gen 

from tornado.concurrent import run_on_executor 
from concurrent.futures import ThreadPoolExecutor # `pip install futures` for python2 

MAX_WORKERS = 16 

class TestHandler(tornado.web.RequestHandler): 
    executor = ThreadPoolExecutor(max_workers=MAX_WORKERS) 

    """ 
    In below function goes your time consuming task 
    """ 

    @run_on_executor 
    def background_task(self): 
     sm = 0 
     for i in range(10 ** 8): 
      sm = sm + 1 

     return sm 

    @tornado.gen.coroutine 
    def get(self): 
     """ Request that asynchronously calls background task. """ 
     res = yield self.background_task() 
     self.write(str(res)) 

class TestHandler2(tornado.web.RequestHandler): 
    @gen.coroutine 
    def get(self): 
     self.write('Response from server') 
     self.finish() 


application = tornado.web.Application([ 
    (r"/A", TestHandler), 
    (r"/B", TestHandler2), 
    ]) 

application.listen(5000) 
IOLoop.instance().start() 

आप कोड ऊपर समाप्त हो जाता है, तो आप http://127.0.0.1:5000/A पर एक computationally महंगा आपरेशन चला सकते हैं, जो निष्पादन ब्लॉक नहीं करता, http://127.0.0.1:5000/B पर जाकर आप http://127.0.0.1:5000/A जाएँ के तुरंत बाद से देखते हैं।

0

यहां मैं टोरनाडो 5.0 के बारे में जानकारी अपडेट करता हूं। टॉरनाडो 5.0 IOLoop.run_in_executor एक नई विधि जोड़ें। Coroutine patterns अध्याय की "कॉलिंग अवरुद्ध कार्यों" में:

एक coroutine से एक अवरुद्ध समारोह कॉल करने के लिए सबसे आसान तरीका IOLoop उपयोग करने के लिए है।run_in_executor, जो वायदा कि coroutines के साथ संगत कर रहे हैं देता है:

@gen.coroutine def call_blocking(): yield IOLoop.current().run_in_executor(blocking_func, args)

इसके अलावा, run_on_executor की documeng में है का कहना है:

यह डेकोरेटर इसी तरह के नाम के साथ भ्रमित नहीं होना चाहिए IOLoop.run_in_executor। सामान्य रूप से, किसी विधि को परिभाषित करते समय इस सजावट का उपयोग करने के बजाय ब्लॉकिंग विधि को कॉल करते समय run_in_executor का उपयोग करने की अनुशंसा की जाती है। यदि टॉरनाडो के पुराने संस्करणों के साथ संगतता की आवश्यकता है, तो कॉल करने वाले पर निष्पादक को परिभाषित करने और execor.submit() का उपयोग करने पर विचार करें।

5.0 संस्करण में, IOLoop.run_in_executor को कॉलिंग अवरुद्ध कार्यों के उपयोग के मामले में अनुशंसा की जाती है।

संबंधित मुद्दे