在Tornado / Python3中启动多处理的TCPServer和HTTPServer?

时间:2016-09-02 03:36:42

标签: python-3.x tornado python-3.5

我有两个Tornado服务器在同一个Python进程中运行。一个是TCPServer,而另一个是HTTPServerTCPServer从某个来源接收数据,然后HTTPServer将该数据广播到连接到所提供的网页的任何客户端。我有两台服务器在tornado.queues.Queue()之间相互通信,其中TCPServer将数据放入队列,HTTPServer从中获取数据并将其发送给网页客户端。< / p>

问题是,如何利用多核?数据只是来自一次来源,因此仅将{1}核专用于TCPServer是有道理的,但由于可以有任意多的客户,我希望通过他们的自己的HTTPServer实例为客户提供服务。

从Tornado文档中,我看到如果所有服务器都不相关,我只需要做这样的事情:

def main():
    app = make_app()
    server = tornado.httpserver.HTTPServer(app)
    server.bind(8888)
    server.start(0)  # forks one process per cpu
    IOLoop.current().start()

但是,由于我在一个进程中运行了两台服务器,因此我无法反映这一点。当我尝试这样做时,我得到一个错误说:

Traceback (most recent call last):
  File "./tcp_server.py", line 28, in <module>
    http_server.start(0)
  File "/usr/local/lib/python3.5/dist-packages/tornado/tcpserver.py", line 205, in start
    process.fork_processes(num_processes)
  File "/usr/local/lib/python3.5/dist-packages/tornado/process.py", line 130, in fork_processes
    raise RuntimeError("Cannot run in multiple processes: IOLoop instance "
RuntimeError: Cannot run in multiple processes: IOLoop instance has already been initialized. You cannot call IOLoop.instance() before calling start_processes()

如何重新组织启动过程,以便在一个进程中拥有TCPServer,在所有其他进程中拥有HTTPServer的多个实例?

import logging
import tornado
import tornado.queues
from buggy_data_server import BuggyDataServer
from buggy_http_server import BuggyHttpServer

if __name__ == "__main__":
    logging.basicConfig(level=logging.DEBUG)
    data_queue = tornado.queues.Queue()

    # Currently, both servers are started in a single process. This needs to be
    # split up into a multiprocess configuration later.
    data_sock = tornado.netutil.bind_sockets(4242)
    data_server = BuggyDataServer(data_queue) # TCPServer
    data_server.add_sockets(data_sock)

    http_sock = tornado.netutil.bind_sockets(8080)
    http_server = BuggyHttpServer(data_queue) # HTTPServer
    http_server.add_sockets(http_sock)
    http_server.start(0)

    tornado.ioloop.IOLoop.instance().start()

1 个答案:

答案 0 :(得分:1)

这属于TCPServer docs的“高级多进程”类别。您需要显式调用fork_processes,而不是让其中一个服务器执行此操作。重新排序您的安装调用,以便在fork之前绑定所有套接字,然后将它们添加到服务器中(根据经验,您希望在fork之前尽可能少地执行):

data_sock = tornado.netutil.bind_sockets(4242)
http_sock = tornado.netutil.bind_sockets(8080)

tornado.process.fork_processes(0)

data_server = BuggyDataServer(data_queue) # TCPServer
data_server.add_sockets(data_sock)
http_server = BuggyHttpServer(data_queue) # HTTPServer
http_server.add_sockets(http_sock)

这将在每个进程中启动HTTP服务器和TCP服务器。如果您只需要运行一个TCP服务器(而不是在该进程中运行HTTP服务器),则可以查看fork_processes的返回值:

http_sock = tornado.netutil.bind_sockets(8080)
proc_num = tornado.process.fork_processes(0)

if proc_num == 0:
    # Close the HTTP sockets in the TCP server's process
    for s in http_sock: s.close()
    BuggyDataServer(data_queue).listen(4242)
else:
    BuggyHttpServer(data_queue).add_sockets(http_sock)