我正在尝试创建一个Python应用程序,其中一个进程(进程'A')接收请求并将其放入ProcessPool(来自concurrent.futures)。在处理此请求时,可能需要将消息传递给第二个进程(进程“B”)。我正在使用龙卷风的iostream模块来帮助包裹连接并获得响应。
进程A无法从ProcessPool执行中成功连接到进程B.我哪里错了?
客户端,它处理初始请求以处理A:
#!/usr/bin/env python
import socket
import tornado.iostream
import tornado.ioloop
def print_message ( data ):
print 'client received', data
s = socket.socket(socket.AF_INET,socket.SOCK_STREAM, 0)
stream = tornado.iostream.IOStream(s)
stream.connect(('localhost',2001))
stream.read_until('\0',print_message)
stream.write('test message\0')
tornado.ioloop.IOLoop().instance().start()
收到初始请求的流程A:
#!/usr/bin/env python
import tornado.ioloop
import tornado.tcpserver
import tornado.iostream
import socket
import concurrent.futures
import functools
def handle_request ( data ):
s = socket.socket(socket.AF_INET,socket.SOCK_STREAM,0)
out_stream = tornado.iostream.IOStream(s)
out_stream.connect(('localhost',2002))
future = out_stream.read_until('\0')
out_stream.write(data+'\0')
return future.result()
class server_a (tornado.tcpserver.TCPServer):
def return_response ( self, in_stream, future ):
in_stream.write(future.result()+'\0')
def handle_read ( self, in_stream, data ):
future = self.executor.submit(handle_request,data)
future.add_done_callback(functools.partial(self.return_response,in_stream))
def handle_stream ( self, in_stream, address ):
in_stream.read_until('\0',functools.partial(self.handle_read,in_stream))
def __init__ ( self ):
self.executor = concurrent.futures.ProcessPoolExecutor()
tornado.tcpserver.TCPServer.__init__(self)
server = server_a()
server.bind(2001)
server.start(0)
tornado.ioloop.IOLoop().instance().start()
进程B,它应该接收来自进程A的中继请求:
#!/usr/bin/env python
import tornado.ioloop
import tornado.tcpserver
import functools
class server_b (tornado.tcpserver.TCPServer):
def handle_read ( self, in_stream, data ):
in_stream.write('server B read'+data+'\0')
def handle_stream ( self, in_stream, address ):
in_stream.read_until('\0',functools.partial(self.handle_read,in_stream))
server = server_b()
server.bind(2002)
server.start(0)
tornado.ioloop.IOLoop().instance().start()
最后,进程A返回的错误是在'read_until'方法中引发的:
ERROR:concurrent.futures:exception calling callback for <Future at 0x10654b890 state=finished raised OSError>
Traceback (most recent call last):
File "/usr/local/lib/python2.7/site-packages/concurrent/futures/_base.py", line 299, in _invoke_callbacks
callback(self)
File "./a.py", line 26, in return_response
in_stream.write(future.result()+'\0')
File "/usr/local/lib/python2.7/site-packages/concurrent/futures/_base.py", line 397, in result
return self.__get_result()
File "/usr/local/lib/python2.7/site-packages/concurrent/futures/_base.py", line 356, in __get_result
raise self._exception
OSError: [Errno 9] Bad file descriptor
答案 0 :(得分:0)
我不是100%确定你为什么会收到这个“错误的文件描述符”错误(concurrent.futures在向后移植到2.7时丢失了回溯信息),但是ProcessPoolExecutor的工作进程中没有运行IOLoop,所以你不能在这个上下文中使用像IOStream这样的Tornado结构(除非你为每个任务启动一个新的IOLoop,但除非你需要与其他异步库兼容,否则这可能没有多大意义。)
我也不确定它是否能够以这种方式混合龙卷风的多进程模式和ProcessPoolExecutor。我认为您可能需要将ProcessPoolExecutor的初始化移动到start(0)调用之后。
答案 1 :(得分:0)
好的,我已经通过更新流程A来解决了这个问题:
def stop_loop ( future ):
tornado.ioloop.IOLoop.current().stop()
def handle_request ( data ):
tornado.ioloop.IOLoop.clear_current()
tornado.ioloop.IOLoop.clear_instance()
s = socket.socket(socket.AF_INET,socket.SOCK_STREAM,0)
out_stream = tornado.iostream.IOStream(s)
out_stream.connect(('localhost',2002))
future = out_stream.read_until('\0')
future.add_done_callback(stop_loop)
out_stream.write(data+'\0')
tornado.ioloop.IOLoop.instance().start()
return future.result()
即使IOLoop以前没有在生成的进程中启动,它在调用当前实例时返回其父循环。清除这些引用允许启动进程的新循环。我不能正式知道这里发生了什么。