我有一个基于代理的模型,其中多个代理由中央进程启动,并通过另一个中央进程进行通信。每个代理和通信过程都通过zmq进行通信。但是,当我启动超过100个代理时,standard_out发送:
无效参数(src / stream_engine.cpp:143)打开的文件太多 (SRC / ipc_listener.cpp:292)
和Mac Os会提示问题报告:
使用libzmq.5.dylib插件时,Python意外退出。
在我看来,问题是打开了太多的上下文。但是如何通过多处理避免这种情况呢?
我附上以下部分代码:
class Agent(Database, Logger, Trade, Messaging, multiprocessing.Process):
def __init__(self, idn, group, _addresses, trade_logging):
multiprocessing.Process.__init__(self)
....
def run(self):
self.context = zmq.Context()
self.commands = self.context.socket(zmq.SUB)
self.commands.connect(self._addresses['command_addresse'])
self.commands.setsockopt(zmq.SUBSCRIBE, "all")
self.commands.setsockopt(zmq.SUBSCRIBE, self.name)
self.commands.setsockopt(zmq.SUBSCRIBE, group_address(self.group))
self.out = self.context.socket(zmq.PUSH)
self.out.connect(self._addresses['frontend'])
time.sleep(0.1)
self.database_connection = self.context.socket(zmq.PUSH)
self.database_connection.connect(self._addresses['database'])
time.sleep(0.1)
self.logger_connection = self.context.socket(zmq.PUSH)
self.logger_connection.connect(self._addresses['logger'])
self.messages_in = self.context.socket(zmq.DEALER)
self.messages_in.setsockopt(zmq.IDENTITY, self.name)
self.messages_in.connect(self._addresses['backend'])
self.shout = self.context.socket(zmq.SUB)
self.shout.connect(self._addresses['group_backend'])
self.shout.setsockopt(zmq.SUBSCRIBE, "all")
self.shout.setsockopt(zmq.SUBSCRIBE, self.name)
self.shout.setsockopt(zmq.SUBSCRIBE, group_address(self.group))
self.out.send_multipart(['!', '!', 'register_agent', self.name])
while True:
try:
self.commands.recv() # catches the group adress.
except KeyboardInterrupt:
print('KeyboardInterrupt: %s,self.commands.recv() to catch own adress ~1888' % (self.name))
break
command = self.commands.recv()
if command == "!":
subcommand = self.commands.recv()
if subcommand == 'die':
self.__signal_finished()
break
try:
self._methods[command]()
except KeyError:
if command not in self._methods:
raise SystemExit('The method - ' + command + ' - called in the agent_list is not declared (' + self.name)
else:
raise
except KeyboardInterrupt:
print('KeyboardInterrupt: %s, Current command: %s ~1984' % (self.name, command))
break
if command[0] != '_':
self.__reject_polled_but_not_accepted_offers()
self.__signal_finished()
#self.context.destroy()
下
答案 0 :(得分:8)
这与zeromq和python无关。它是底层操作系统,只允许同时打开的文件达到一定阈值。此限制包括普通文件,但也包括套接字连接。
您可以使用ulimit -n
查看当前限制,它可能默认为1024
。运行服务器或具有其他原因(例如多处理)的计算机通常需要将此限制设置为更高或仅设置为unlimited
。 - More info about ulimit
。
此外,还有另一个global limit,但是我不得不调整它。
一般来说,如果你真的需要那么多代理人,你应该问问自己。通常,X
/ 2X
工作进程应该足够,其中X
对应于您的CPU数。
答案 1 :(得分:7)
可能性不是太多的情况,它的插座太多了。通过您的回购,我看到您(正确)使用IPC作为您的交通工具; IPC使用文件描述符作为“地址”来在不同进程之间来回传递数据。如果我正确阅读,每个进程最多可以打开7个套接字,这样就可以快速加入。我敢打赌,如果你在代码中间做一些调试,你会发现它在创建最后一个上下文时没有失败,但是当最后一个套接字推动了边缘上的打开文件限制时。
我的理解是,开放FD的典型用户限制大约是1000,所以在大约100个代理商中,你只需要为你的套接字推送700个开放FD。剩下的可能只是典型的。根据您的情况,将您的限制提高到10,000,应该没有问题。否则,您将不得不重写每个进程使用较少的套接字以获得更高的进程限制。