2011-03-03 45 views
2

我想實現一個基於龍捲風的Web服務,它可以爲用戶提供數據庫查詢服務。我使用pyodbc模塊連接到數據庫並執行查詢。實際上,我發現打印查詢結果需要很長時間。也就是說,如果我用下面的代碼打印查詢結果與Tornado和pyodbc的異步調用

while 1: 
    data = cursor.fetchone() 
    if not data: break 
    self.write(data + '\n') 
    self.flush() 

和SQL命令是一樣的東西

select * from <a large dummy table> 

龍捲風,直到循環結束不打印查詢結果。這需要很長時間。

我想使用龍捲風的非阻塞異步功能,使其他用戶也能夠使用Web服務,即使打印當前用戶的查詢請求的循環尚未完成。

所以我寫的東西,如:

@tornado.web.asynchronous 
def get(self): 
    try: 
     cnxn = pyodbc.connect(self.server, self.driver, self.table, self.uid, self.pwd) 
    except Exception, e: 
     print e 
     return 

    try: 
     self.cur = cnxn.execute(self.sql) 
    except Exception, e: 
     print e 
     return 

    self.wait_for_query(callback=self.async_callback(self.on_finish)) 

def wait_for_query(self, callback): 
    while 1: 
     data = self.cur.fetchone() 
     if not data: break 
     self.write(data) 
     self.flush() 
    callback() 

def on_finish(self): 
    self.finish() 

我看到這篇文章: Asynchronous COMET query with Tornado and Prototype ,知道我的解決辦法是行不通的。但我當然不能使用add_timeout,因爲我無法弄清楚迭代持續的時間。那麼,我如何通過這個工作來實現我的目標呢?

回答

0

爲了讓單線程Tornado服務器在這樣的請求中是異步的,您必須將控制權交還給I/O循環。試試這個:

class LongRequestHandler(tornado.web.RequestHandler): 
    def database_callback(self): 
     data = self.cur.fetchone() 
     if not data: 
      self.finish() 
      self.cnxn.close() 
     else: 
      self.write(data) 
      self.flush() 
      tornado.ioloop.IOLoop.instance().add_callback(self.database_callback) 

    @tornado.web.asynchronous 
    def get(self): 
     try: 
      self.cnxn = pyodbc.connect(self.server, self.driver, self.table, self.uid, self.pwd) 
     except Exception, e: 
      print e 
      return 

     try: 
      self.cur = self.cnxn.execute(self.sql) 
     except Exception, e: 
      print e 
      return 

     tornado.ioloop.IOLoop.instance().add_callback(self.database_callback) 

但值得注意的是,每個數據庫提供者都是不同的。我的理解是,在MySQL中,大部分時間/處理實際上將花費在execute()調用上,而不是循環遍歷數據,因爲MySQL會處理整個查詢並返回完整的結果集。如果您使用的是同樣的數據庫提供程序,則可能需要在位於Tornado後面的工作進程中處理這樣的請求。

編輯我的例子只是一個例子。實際上,在返回之前,你需要測試你的回調函數,並且可能循環了好幾行,否則你會浪費IO循環中函數間很多CPU時間切換,而不是實際處理請求。在做了一些測試後,我擔心的是MySQL是真實的 - 執行/查詢語句本身就是導致鎖定的語句,所以這種解決方案在這種情況下確實無濟於事。