2012-10-24 15 views
11

तूफान का उपयोग करना, मैं एक प्राप्त अनुरोध है कि एक लंबा समय लगता है क्योंकि यह किसी अन्य वेब सेवा के लिए कई अनुरोध करता और डाटा को संसाधित करता है, मिनट पूरी तरह से पूरा करने के लिए ले सकता है। मैं नहीं चाहता कि यह पूरे वेब सर्वर को अन्य अनुरोधों का जवाब देने से रोक देगा, जो वर्तमान में करता है।तूफान अवरुद्ध अतुल्यकालिक अनुरोध

मैं यह समझ के रूप में, तूफान एकल लड़ी है और तालमेल के प्रत्येक अनुरोध को निष्पादित करता है, भले ही यह उनके एसिंक्रोनस रूप से संभालती है (अब भी है कि बिट पर उलझन में)। लंबी प्रक्रिया के कुछ हिस्सों हैं जो सर्वर को अन्य अनुरोधों (संभव समाधान?) को संभालने की अनुमति देने के लिए पॉज़ पॉइंट्स हो सकते हैं। मैं इसे एक ही कार्यकर्ता के साथ हेरोकू पर चला रहा हूं, इसलिए यह सुनिश्चित न करें कि यह एक नए थ्रेड या मल्टीप्रोसेसिंग में कैसे अनुवाद करता है, जिसमें मुझे अजगर के साथ कोई अनुभव नहीं है।

यहां मैं जो करने की कोशिश कर रहा हूं: क्लाइंट प्रक्रिया शुरू करने के लिए कॉल प्राप्त करता है, फिर मैं स्थिति की जांच करने और नई जानकारी के साथ पृष्ठ को अद्यतन करने के लिए हर 5 सेकंड में कॉल प्राप्त करता हूं (लंबी मतदान काम भी करते हैं लेकिन एक ही मुद्दे में चल रहे हैं)। समस्या यह है कि लंबी प्रक्रिया शुरू करने से सभी नए अनुरोध (या नए लंबे मतदान सत्र) को पूरा होने तक ब्लॉक मिल जाता है।

क्या इस लंबी कॉल को बंद करने का कोई आसान तरीका है और इस प्रक्रिया में पूरे वेब सर्वर को अवरुद्ध नहीं किया गया है? क्या मैं कुछ भी कहने के लिए कोड में डाल सकता हूं .. "रोकें, लंबित अनुरोधों को संभालें, फिर जारी रखें"?

मुझे प्रोसेस हैडलर पर एक अनुरोध प्राप्त करने की आवश्यकता है। मुझे प्रोसेस हैडलर चल रहा है, जबकि मुझे स्टेटसहैंडलर से पूछने में सक्षम होना जारी रखना होगा।

उदाहरण:

class StatusHandler(tornado.web.RequestHandler): 
    @tornado.web.asynchronous 
    def get(self): 
     self.render("status.html") 

class ProcessHandler(tornado.web.RequestHandler): 
    @tornado.web.asynchronous 
    def get(self): 
     self.updateStatus("0") 
     result1 = self.function1() 
     self.updateStatus("1") 
     result2 = self.function2(result1) 
     self.updateStatus("2") 
     result3 = self.function3(result2) 
     self.updateStatus("3") 
     self.finish() 
+0

क्या आपने tornado.gen मॉड्यूल का प्रयास किया है? http://www.tornadoweb.org/documentation/gen.html –

+0

आप एक अतुल्यकालिक कॉल के रूप में उस पर टिप्पणी करने के लिए याद किया: जोड़ें: अपने GET तरीकों –

+0

पर @asynchronous andyboot हाँ, मैं अपने प्राप्त तरीकों – JeffG

उत्तर

17

यहाँ Async HTTP ग्राहक और चीजों को सरल बनाने के लिए gen.Task मॉड्यूल का उपयोग करता है एक पूर्ण नमूना तूफान अनुप्रयोग है।

आप अधिक gen.Task के बारे में डॉक्स में आपको लगता है कि आप वास्तव में एक ही समय में एक से अधिक अनुरोध प्रेषण कर सकते हैं देखेंगे पढ़ें। यह टोरनाडो के मूल विचार का उपयोग कर रहा है जहां सब कुछ अवरुद्ध नहीं है और अभी भी एक प्रक्रिया को बनाए रखता है।

अपडेट: मैंने यह दिखाने के लिए एक थ्रेड हैंडलर जोड़ा है कि आप दूसरे थ्रेड में कैसे काम भेज सकते हैं और callback() प्राप्त होने पर प्राप्त कर सकते हैं।

import os 
import threading 
import tornado.options 
import tornado.ioloop 
import tornado.httpserver 
import tornado.httpclient 
import tornado.web 
from tornado import gen 
from tornado.web import asynchronous 

tornado.options.define('port', type=int, default=9000, help='server port number (default: 9000)') 
tornado.options.define('debug', type=bool, default=False, help='run in debug mode with autoreload (default: False)') 

class Worker(threading.Thread): 
    def __init__(self, callback=None, *args, **kwargs): 
     super(Worker, self).__init__(*args, **kwargs) 
     self.callback = callback 

    def run(self): 
     import time 
     time.sleep(10) 
     self.callback('DONE') 

class Application(tornado.web.Application): 
    def __init__(self): 
     handlers = [ 
      (r"/", IndexHandler), 
      (r"/thread", ThreadHandler), 
     ] 
     settings = dict(
      static_path = os.path.join(os.path.dirname(__file__), "static"), 
      template_path = os.path.join(os.path.dirname(__file__), "templates"), 
      debug = tornado.options.options.debug, 
     ) 
     tornado.web.Application.__init__(self, handlers, **settings) 

class IndexHandler(tornado.web.RequestHandler): 
    client = tornado.httpclient.AsyncHTTPClient() 

    @asynchronous 
    @gen.engine 
    def get(self): 
     response = yield gen.Task(self.client.fetch, "http://google.com") 

     self.finish("Google's homepage is %d bytes long" % len(response.body)) 

class ThreadHandler(tornado.web.RequestHandler): 
    @asynchronous 
    def get(self): 
     Worker(self.worker_done).start() 

    def worker_done(self, value): 
     self.finish(value) 

def main(): 
    tornado.options.parse_command_line() 
    http_server = tornado.httpserver.HTTPServer(Application()) 
    http_server.listen(tornado.options.options.port) 
    tornado.ioloop.IOLoop.instance().start() 

if __name__ == "__main__": 
    main() 
+0

मैंने अपने फ़ंक्शन को जेन में लपेट लिया। टास्क लेकिन यह अभी भी वही काम करता है। मैंने एक ऐसा गेट बनाया जिसकी एकाधिक प्रतिक्रिया थी = प्राप्त करें। टास्क()। मुझे उन्हें एक ही समय में निष्पादित करने की आवश्यकता नहीं है .. वास्तव में उन्हें धारावाहिक होने की आवश्यकता है, लेकिन अनुरोध प्राप्त होने पर किसी भी अन्य अनुरोध को अवरुद्ध कर दिया गया है। – JeffG

+0

मैंने ऊपर अपना उदाहरण अपडेट किया है। मैंने gen.ask() और सब कुछ काम करने के साथ सभी कार्यों को लपेटने की कोशिश की है, लेकिन यह अभी भी स्थिति समाप्त होने तक स्टेटसहैंडलर पर प्रश्नों का जवाब देने से मुझे अवरुद्ध कर दिया है। – JeffG

+0

आपके उदाहरण में self.function1() एक _pure_ पायथन फ़ंक्शन है जो बाहरी सेवाओं के लिए कोई अन्य कॉल नहीं करता है?मूल धारणा यह थी कि इसे किसी अन्य सेवा के लिए बुलाया गया था और आप उस पर अवरुद्ध थे। – koblas

5

कोब्लास का समाधान बहुत अच्छा है। यहां एक विकल्प है जो tornado.gen

import tornado.ioloop 
import tornado.web 
import tornado.gen 
import tornado.concurrent 
import time 
from threading import Thread 
from functools import wraps 

def run_async(func): 
    @wraps(func) 
    def async_func(*args, **kwargs): 
    func_hl = Thread(target = func, args = args, kwargs = kwargs) 
    func_hl.start() 
    return func_hl 

    return async_func 

@run_async 
def sleeper(callback): 
    i = 0 
    while i <= 10: 
    print i 
    time.sleep(1) 
    i += 1 
    callback('DONE') 


class MainHandler(tornado.web.RequestHandler): 
    @tornado.web.asynchronous 
    @tornado.gen.coroutine 
    def get(self): 
     response = yield tornado.gen.Task(sleeper) 
     self.write(response) 
     self.finish() 

class OtherHandler(tornado.web.RequestHandler): 
    def get(self): 
     self.write('hello world') 
     print 'in other' 
     self.finish() 
संबंधित मुद्दे