处理超出范围的选择

时间:2013-02-13 12:35:15

标签: python linux ipc pipe

许多(> 1000)工作人员(流程)做了一些并希望将他们的工作结果保存在数据库中。工作结果是JSON对象。工人每秒生成1-5个JSON对象。数据库保护程序是分离的过程。用于将JSON对象从worker转移到saver的单向连接是多处理。管道。管道数量等于工人数量。

定期进行保护过程сall:

def recv_data(self):
    data = []
    for pipe in self.data_pipe_pool:
        if pipe.poll():
            data.append(pipe.recv())
    return data

self.data_pipe_pool - 来自工人的管道列表。

如果我跑100个工人,一切正常。如果我运行> 1000名工人,我会得到例外:

2013-02-13T15:17:40.731429
Traceback (most recent call last):
  File "saver.py", line 44, in run
    profile = self.poll_data()
  File "saver.py", line 116, in poll_data
    ret = self.recv_data()
  File "saver_unit.py", line 127, in recv_data
    if pipe.poll():
IOError: handle out of range in select()

我知道这是select()来电,并且:

  

在GNU / Linux系统中,FD_SETSIZE通常定义为1024

但在哪里叫select?如果在pipe.poll()中,为什么我超出了FD_SETSIZE限制,我会分别为1个管道调用pipe.poll()?我可以通过此调用select在哪里观看python语言来源?

哪种解决方法不超过FD_SETSIZE限制或不使用select

4 个答案:

答案 0 :(得分:2)

如果您查看select manual page,您会看到:

  

执行FD_CLR()或FD_SET(),其值为fd为负或等于或大于FD_SETSIZE将导致未定义的行为。

这意味着,如果select调用中的场景后面使用了poll(似乎很可能),并且您的文件描述符大于FD_SETSIZE(很可能,如果您已经结束) 1000管道)然后结果可以是任何东西。

答案 1 :(得分:0)

你有没有想过使用像beanstalkd这样的东西,因为它听起来你有一个从工人到服务器的管道,而通常你有1000个工人,然后10个服务器从结果队列中读取将它们存储在数据库中。

好处是,您的工作人员可能比与服务器交谈花费更多时间来完成工作,但是您已经向该服务器打开了管道。

您可以拥有1000名工作人员从中获取的“作业队列”以及他们存储结果的“结果队列”。此后,您可以让许多服务器从“结果队列”中取出来存储在数据库中。

这是一个很长的说法,“至少你不会用完文件句柄”。

答案 2 :(得分:0)

我使用epoll解决了这个问题。解决方案非常简单:

def set_data_pipe_poll(self, data_pipe_poll):
    self.epoll = select.epoll()
    for p in data_pipe_poll:
        self.epoll.register(p, select.EPOLLIN)
    self.data_pipe_poll = data_pipe_poll

def recv_data(self):
    data = []
    events = self.epoll.poll(timeout = 0)
    for fileno, _ in events:
        p = filter(lambda x: x.fileno() == fileno, self.data_pipe_poll)[0]
        data.append(p.recv())
    return data

当我致电epoll.poll()时,我不会致电select

答案 3 :(得分:0)

我有类似的问题。我为每个worker使用了multiprocessing.Queue,当worker的数量大约为600时,队列方法失败了IOError: handle out of range in select()

我在官方错误跟踪器中发现导致问题的issue。它固定在2.7.4(我有2.7.3)。更新python包解决了这个问题。