久久久久久久视色,久久电影免费精品,中文亚洲欧美乱码在线观看,在线免费播放AV片

<center id="vfaef"><input id="vfaef"><table id="vfaef"></table></input></center>

    <p id="vfaef"><kbd id="vfaef"></kbd></p>

    
    
    <pre id="vfaef"><u id="vfaef"></u></pre>

      <thead id="vfaef"><input id="vfaef"></input></thead>

    1. 站長資訊網(wǎng)
      最全最豐富的資訊網(wǎng)站

      Tornado實現(xiàn)多進程/多線程的HTTP服務(wù)

      用Tornado Web服務(wù)的基本流程

      1.實現(xiàn)處理請求的Handler,該類繼承自tornado.web.RequestHandler,實現(xiàn)用于處理請求的對應(yīng)方法如:get、post等。返回內(nèi)容用self.write方法輸出。

      2.實例化一個Application。構(gòu)造函數(shù)的參數(shù)是一個Handlers列表,通過正則表達式,將請求與Handler對應(yīng)起來。通過dict將Handler需要的其他對象以參數(shù)的方式傳遞給Handler的initialize方法。

      3.初始化一個tornado.httpserver.HTTPServer對象,構(gòu)造函數(shù)的參數(shù)是上一步的Application對象。

      4.為HTTPServer對象綁定一個端口。

      5.開始IOLoop。

      需要用到的特性

      由于tornado的亮點是異步請求,所以這里首先想到的是將所有請求都改造為異步的。但是這里遇到一個問題,就是異步函數(shù)內(nèi)一定不能有阻塞調(diào)用出現(xiàn),否則整個IOLoop都會被卡住。這就要求徹底地去改造服務(wù),將所有IO或是用時較長的請求都改造為異步函數(shù)。這個工程量是非常大的,需要去修改已有的代碼。因此,我們考慮用線程池的方式去實現(xiàn)。當(dāng)一個線程阻塞在某個請求或IO時,其他線程或IOLoop會繼續(xù)執(zhí)行。

      另外一個瓶頸就是GIL限制了CPU的并發(fā)數(shù)量,因此考慮用子進程的方式增加進程數(shù),提高服務(wù)能力上限。

      綜合上面的分析,大致用以下方案:

      1.通過子進程的方式復(fù)制多個進程,使子進程中的只讀頁指向同一個物理頁。

      2.線程池。回避異步改造的工作量,增加IO的并發(fā)量。

      測試代碼

      首先測試線程池,測試用例為:

      對sleep頁面同時發(fā)出兩個請求:

      1.在線程池中運行的函數(shù)(這里是self.block_task)能夠同時執(zhí)行。表現(xiàn)為在控制臺交替打印出數(shù)字。

      2.兩個get請求幾乎同時返回,在瀏覽器上顯示返回的內(nèi)容。

      線程池的測試代碼如下:

      import os
      import sys
      import time
       
      import tornado.httpserver
      import tornado.ioloop
      import tornado.options
      import tornado.web
      import tornado.gen
      from tornado.concurrent import run_on_executor
      from concurrent.futures import ThreadPoolExecutor
      from tornado.options import define, options
       
      class HasBlockTaskHandler(tornado.web.RequestHandler):
          executor = ThreadPoolExecutor(20)  #起線程池,由當(dāng)前RequestHandler持有
         
          @tornado.gen.coroutine
          def get(self):
              strTime = time.strftime(“%Y-%m-%d %H:%M:%S”)
              print “in get before block_task %s” % strTime
              result = yield self.block_task(strTime)
              print “in get after block_task”
              self.write(“%s” % (result))
       
          @run_on_executor
          def block_task(self, strTime):
              print “in block_task %s” % strTime
              for i in range(1, 16):
                  time.sleep(1)
                  print “step %d : %s” % (i, strTime)
              return “Finish %s” % strTime
       
      if __name__ == “__main__”:
          tornado.options.parse_command_line()
          app = tornado.web.Application(handlers=[(r”/sleep”, HasBlockTaskHandler)], autoreload=False, debug=False)
          http_server = tornado.httpserver.HTTPServer(app)
          http_server.bind(8888)
          tornado.ioloop.IOLoop.instance().start()

      整個代碼里有幾個位置值得關(guān)注:

      1.executor = ThreadPoolExecutor(20)。這是給Handler類初始化了一個線程池。其中concurrent.futures不屬于tornado,是Python的一個獨立模塊,在python3中是內(nèi)置模塊,python2.7需要自己安裝。

      2.修飾符@run_on_executor。這個修飾符將同步函數(shù)改造為在executor(這里是線程池)上運行的異步函數(shù),內(nèi)部實現(xiàn)是將被修飾的函數(shù)submit到executor,返回一個Future對象。

      3.修飾符@tornado.gen.coroutine。被這個修飾符修飾的函數(shù),是一個以同步函數(shù)方式編寫的異步函數(shù)。原本通過callback方式編寫的異步代碼,有了這個修飾符,可以通過yield一個Future的方式來寫。被修飾的函數(shù)在yield了一個Future對象后將會被掛起,F(xiàn)uture對象的結(jié)果返回后繼續(xù)執(zhí)行。

      運行代碼后,在兩個不同瀏覽器上訪問sleep頁面,得到了想要的效果。這里有一個小插曲,就是如果在同一瀏覽器的兩個tab上進行測試,是無法看到想要的效果。第二個get請求會被block,直到第一個get請求返回,服務(wù)端才開始處理第二個get請求。這讓我一度覺得多線程沒有生效,用了半天時間查了很多資料,才看到是瀏覽器把相同的第二個請求block了,具體鏈接參考這里。

      由于tornado很方便地支持多進程模型,多進程的使用要簡單很多,在以上例子中,只需要對啟動部分稍作改動即可。具體代碼如下所示:

      if __name__ == “__main__”:
          tornado.options.parse_command_line()
          app = tornado.web.Application(handlers=[(r”/sleep”, HasBlockTaskHandler)], autoreload=False, debug=False)
          http_server = tornado.httpserver.HTTPServer(app)
          http_server.bind(8888)
          print tornado.ioloop.IOLoop.initialized()
          http_server.start(5)
          tornado.ioloop.IOLoop.instance().start()

      需要注意的地方有兩點:

      app = tornado.web.Application(handlers=[(r”/sleep”, HasBlockTaskHandler)], autoreload=False, debug=False),在生成Application對象時,要將autoreload和debug兩個參數(shù)至為False。也就是需要保證在fork子進程之前IOLoop是未被初始化的。這個可以通過tornado.ioloop.IOLoop.initialized()函數(shù)來跟。
      http_server.start(5)在啟動IOLoop之前通過start函數(shù)設(shè)置進程數(shù)量,如果設(shè)置為0表示每個CPU都啟動一個進程。

      最后的效果是可以看到n+1個進程在運行,且公用同一個端口。

      贊(0)
      分享到: 更多 (0)
      網(wǎng)站地圖   滬ICP備18035694號-2    滬公網(wǎng)安備31011702889846號