簡體   English   中英

並發龍卷風中的繁重任務

[英]concurrency of heavy tasks in tornado

我的代碼:

import tornado.tcpserver
import tornado.ioloop
import itertools
import socket
import time

class Talk():
    def __init__(self, id):
        self.id = id

    @tornado.gen.coroutine
    def on_connect(self):
        try:
            while "connection alive":
                self.said = yield self.stream.read_until(b"\n") 

                response = yield tornado.gen.Task(self.task)     ### LINE 1

                yield self.stream.write(response)                   ### LINE 2

        except tornado.iostream.StreamClosedError:
            print('error: socket closed')
        return

    @tornado.gen.coroutine
    def task(self):
        if self.id == 1:
           time.sleep(3)  # sometimes request is heavy blocking
        return b"response"

    @tornado.gen.coroutine
    def on_disconnect(self):
        yield []


class Server(tornado.tcpserver.TCPServer):

    def __init__(self, io_loop=None, ssl_options=None, max_buffer_size=None):

        tornado.tcpserver.TCPServer.__init__(self,
            io_loop=io_loop,
            ssl_options=ssl_options,
            max_buffer_size=max_buffer_size)

        self.talk_id_alloc = itertools.count(1)
        return


    @tornado.gen.coroutine
    def handle_stream(self, stream, address):
        talk_id = next(self.talk_id_alloc)
        talk = Talk(talk_id)

        stream.set_close_callback(talk.on_disconnect)
        stream.socket.setsockopt(socket.IPPROTO_TCP, socket.TCP_NODELAY, 1)
        stream.socket.setsockopt(socket.IPPROTO_TCP, socket.SO_KEEPALIVE, 1)

        talk.stream = stream

        yield talk.on_connect()

        return

Server().listen(8888)
tornado.ioloop.IOLoop.instance().start()

問題:

我需要龍卷風作為tcp服務器-它似乎是處理許多計算量較低的請求的不錯選擇。

然而:

  99% of requests will last less than 0,05 sec, but
  1% of them can last even 3 sec (special cases).
  single response must be returned at once, not partially.

這里最好的方法是什么? 如何獲得LINE#1不會阻塞超過0.1秒的代碼

 yield tornado.gen.with_timeout(
    datetime.timedelta(seconds=0.1), tornado.gen.Task(self.task))

從我這里不起作用-什么都不做

 tornado.ioloop.IOLoop.current().add_timeout(
      datetime.timedelta(seconds=0.1),
      lambda: result.set_exception(TimeoutError("Timeout"))) 

要么一無所有。

尋找更好的解決方案:

  • 任務可以檢測是否需要大量計算(API ...)-使用超時嗎,然后運行/分叉到另一個線程甚至進程,然后發送給龍卷風服務器執行-稍后從結果隊列(消費者/生產者)“接收”我我不是否想在超時情況下殺死繁重的任務而不保存結果,然后在特殊的包裝器中重新打開任務-消費者/生產者模式應該適用於所有任務?

  • 在阻止電流時添加新的ioloop-如何檢測阻止?

我在龍卷風中看不到任何解決方案。

第1行中的任務可能很簡單(〜99%)或很復雜,可能需要:

 I/O:
 - disk/DB access
 - ram/redis access
 network:
 - API call
 CPU:
 - algorithms, regex

(最糟糕的任務將完成上述所有操作)。 我僅在開始執行任務時才知道它是什么樣的任務(權重),所以適當的做法是在單獨的線程中使用任務隊列。 我不想延遲簡單/快速的任務。

因此,如果您設法取消繁重的任務,我建議您在超時之前取消它們,然后將它們生成到另一個線程。 在性能方面,這不是理想的(GIL),但可以防止龍卷風阻塞-這是您的最終目標。

有關如何執行此操作的不錯文章,可在以下位置找到: http : //lbolla.info/blog/2013/01/22/blocking-tornado

如果您想走得更遠,可以使用諸如芹菜之類的東西,在這里您可以透明地分流到其他進程,盡管重得多。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM