许多(> 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
?
答案 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包解决了这个问题。