zeromq和python多处理,打开的文件太多了

时间:2015-07-04 12:14:12

标签: zeromq python-multiprocessing

我有一个基于代理的模型,其中多个代理由中央进程启动,并通过另一个中央进程进行通信。每个代理和通信过程都通过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()

整个代码位于http://www.github.com/DavoudTaghawiNejad/abce

2 个答案:

答案 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,应该没有问题。否则,您将不得不重写每个进程使用较少的套接字以获得更高的进程限制。