2013-02-13 68 views
1

许多(> 1000)的工人(过程)做一些和想要保存在数据库中的工作成果。工作结果是JSON对象。工人每秒产生1-5个JSON对象。数据库保存程序是分开的过程。从工作者到保护者传输JSON对象的单向连接是multiprocessing.Pipe。管道数量等于工人数量。处理超出范围选择

在保护过程中定期с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()通话和:

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

但是那里叫select?如果在pipe.poll()中,为什么我超过了FD_SETSIZE限制,我打电话pipe.poll()单个管道?我在哪里可以通过这个电话select来观看Python语言资源?

什么解决办法不超过FD_SETSIZE限制或不使用select

回答

2

如果您检查select manual page,你会发现:

与FD的值是负值或等于或大于FD_SETSIZE会导致不确定的行为执行FD_CLR()或FD_SET() 。

这意味着,如果使用select幕后在poll调用(很可能),你有文件描述符大于FD_SETSIZE(很可能,如果你有超过1000个管道),那么结果可能是什么。

+0

感谢您的回答。 如何避免阴影调用'select'?可能是存在管道(或over object)epoll API在低级别? – sheh 2013-02-13 15:05:01

0

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

的好处是,它很可能是你的工人正在采取更多的时间做他们的工作比谈话的服务器,但你得开到该服务器的管道。

你可以有一个“工作队列”,工人的您1000年从采取和“结果队列”,它们存储在结果。此后,您可以将许多服务器从“结果队列”中取出以存储在数据库中。

这是说:“至少,那么你会不会文件句柄用完了”很长的路要走。

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

0

我有类似的问题。我为每个工人使用multiprocessing.Queue,当工人数量大约为600时,排队方法失败,IOError: handle out of range in select()。我发现issue在导致问题的官方bug跟踪器中。它被固定在2.7.4(我有2.7.3)。 python包的更新解决了这个问题。