[英]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.