Python OSError:[Errno 24]在Twisted中使用reactor.run()时打开的文件过多
我遇到了一个奇怪的问题:我运行了大量的Python OSError:[Errno 24]在Twisted中使用reactor.run()时打开的文件过多,python,python-2.7,twisted,centos7,Python,Python 2.7,Twisted,Centos7,我遇到了一个奇怪的问题:我运行了大量的utils.getProcessOutputAdvalue('cmd',[args])命令,结果取决于我是使用task.react()还是reactor.run() 当使用高于400的limit时(在我的情况下),我得到以下错误: Upon execvpe echo ['echo', 'Testing 0...'] in environment id 42131264 :Traceback (most recent call last): File "/
utils.getProcessOutputAdvalue('cmd',[args])
命令,结果取决于我是使用task.react()
还是reactor.run()
当使用高于400的limit
时(在我的情况下),我得到以下错误:
Upon execvpe echo ['echo', 'Testing 0...'] in environment id 42131264
:Traceback (most recent call last):
File "/home/vagrant/.env/sm/lib/python2.7/site-packages/Twisted-15.5.0-py2.7-linux-x86_64.egg/twisted/internet/process.py", line 428, in _fork
self._setupChild(**kwargs)
File "/home/vagrant/.env/sm/lib/python2.7/site-packages/Twisted-15.5.0-py2.7-linux-x86_64.egg/twisted/internet/process.py", line 803, in _setupChild
for fd in _listOpenFDs():
File "/home/vagrant/.env/sm/lib/python2.7/site-packages/Twisted-15.5.0-py2.7-linux-x86_64.egg/twisted/internet/process.py", line 638, in _listOpenFDs
return detector._listOpenFDs()
File "/home/vagrant/.env/sm/lib/python2.7/site-packages/Twisted-15.5.0-py2.7-linux-x86_64.egg/twisted/internet/process.py", line 553, in _listOpenFDs
self._listOpenFDs = self._getImplementation()
File "/home/vagrant/.env/sm/lib/python2.7/site-packages/Twisted-15.5.0-py2.7-linux-x86_64.egg/twisted/internet/process.py", line 576, in _getImplementation
after = impl()
File "/home/vagrant/.env/sm/lib/python2.7/site-packages/Twisted-15.5.0-py2.7-linux-x86_64.egg/twisted/internet/process.py", line 606, in _procFDImplementation
return [int(fd) for fd in self.listdir(dname)]
OSError: [Errno 24] Too many open files: '/proc/23421/fd'
Unhandled error in Deferred:
如果我使用的是task.react()
在简历中:
:OKpython pyerr.py-l100-r
:OKpython pyerr.py-l100-t
:OKpython pyerr.py-l100-w
:OSERRpython pyerr.py-l400-r
:OKpython pyerr.py-l400-t
:OSERRpython pyerr.py-l400-w
task.react
,我不想停止reactor)
我一直认为,task.react
只是在延迟完成后停止反应堆,但我想它做的不止这些
编辑:这里有一个
pstree
比较任务。反应
vs反应器。运行
#!/usr/bin/env python
# -*- coding: utf-8 -*-
from progress.bar import IncrementalBar
from twisted.internet import defer
from twisted.internet import task
from twisted.internet import utils
from twisted.python import usage
class Options(usage.Options):
optFlags = [['reactor', 'r', 'Use reactor.run().'],
['task', 't', 'Use task.react().'],
['cwr', 'w', 'Use callWhenRunning().']]
optParameters = [['limit', 'l', 255, 'Number of file descriptors to open.'],
['cmd', 'c', 'echo Testing {i}...', 'Command to run.']]
def run(opt):
limit = int(opt['limit'])
cmd, args = opt['cmd'].split(' ', 1)
bar = IncrementalBar('Running {cmd}'.format(cmd=opt['cmd']), max=limit)
requests = []
for i in range(0, limit):
try:
_args = args.format(i=i)
args = _args
except KeyError:
pass
requests.append(utils.getProcessOutputAndValue('echo', [args]))
bar.next()
bar.finish()
return defer.gatherResults(requests)
@defer.inlineCallbacks
def main(reactor, opt):
d = defer.Deferred()
limit = int(opt['limit'])
cmd, args = opt['cmd'].split(' ', 1)
bar = IncrementalBar('Running {cmd}'.format(cmd=opt['cmd']), max=limit)
for i in range(0, limit):
try:
_args = args.format(i=i)
args = _args
except KeyError:
pass
yield utils.getProcessOutputAndValue('echo', [args])
bar.next()
bar.finish()
defer.returnValue(d.callback(True))
if __name__ == '__main__':
opt = Options()
opt.parseOptions()
if opt['reactor']:
from twisted.internet import reactor
task.deferLater(reactor, 0, run, opt)
reactor.run()
elif opt['task']:
from twisted.internet.task import react
react(main, [opt])
elif opt['cwr']:
from twisted.internet import reactor
reactor.callWhenRunning(run, opt)
reactor.run()
reactor.run(python pyerr.py-l400-r):
init-+-VBoxService---7*[{VBoxService}]
|-acpid
|-atd
|-cron
|-dbus-daemon
|-dhclient
|-6*[getty]
|-master-+-pickup
| `-qmgr
|-mysqld---18*[{mysqld}]
|-nginx---4*[nginx]
|-php5-fpm---2*[php5-fpm]
|-puppet---{puppet}
|-rpc.idmapd
|-rpc.statd
|-rpcbind
|-rsyslogd---3*[{rsyslogd}]
|-ruby---{ruby}
|-sshd-+-3*[sshd---sshd---sftp-server]
| |-sshd---sshd---2*[sftp-server]
| |-sshd---sshd---bash---pstree
| `-sshd---sshd---bash---python-+-323*[echo]
| `-5*[python]
|-systemd-logind
|-systemd-udevd
|-upstart-file-br
|-upstart-socket-
`-upstart-udev-br
init-+-VBoxService---7*[{VBoxService}]
|-acpid
|-atd
|-cron
|-dbus-daemon
|-dhclient
|-6*[getty]
|-master-+-pickup
| `-qmgr
|-mysqld---18*[{mysqld}]
|-nginx---4*[nginx]
|-php5-fpm---2*[php5-fpm]
|-puppet---{puppet}
|-rpc.idmapd
|-rpc.statd
|-rpcbind
|-rsyslogd---3*[{rsyslogd}]
|-ruby---{ruby}
|-sshd-+-3*[sshd---sshd---sftp-server]
| |-sshd---sshd---2*[sftp-server]
| |-sshd---sshd---bash---pstree
| `-sshd---sshd---bash---python---echo
|-systemd-logind
|-systemd-udevd
|-upstart-file-br
|-upstart-socket-
`-upstart-udev-br
task.react(python-pyerr.py-l400-t):
init-+-VBoxService---7*[{VBoxService}]
|-acpid
|-atd
|-cron
|-dbus-daemon
|-dhclient
|-6*[getty]
|-master-+-pickup
| `-qmgr
|-mysqld---18*[{mysqld}]
|-nginx---4*[nginx]
|-php5-fpm---2*[php5-fpm]
|-puppet---{puppet}
|-rpc.idmapd
|-rpc.statd
|-rpcbind
|-rsyslogd---3*[{rsyslogd}]
|-ruby---{ruby}
|-sshd-+-3*[sshd---sshd---sftp-server]
| |-sshd---sshd---2*[sftp-server]
| |-sshd---sshd---bash---pstree
| `-sshd---sshd---bash---python-+-323*[echo]
| `-5*[python]
|-systemd-logind
|-systemd-udevd
|-upstart-file-br
|-upstart-socket-
`-upstart-udev-br
init-+-VBoxService---7*[{VBoxService}]
|-acpid
|-atd
|-cron
|-dbus-daemon
|-dhclient
|-6*[getty]
|-master-+-pickup
| `-qmgr
|-mysqld---18*[{mysqld}]
|-nginx---4*[nginx]
|-php5-fpm---2*[php5-fpm]
|-puppet---{puppet}
|-rpc.idmapd
|-rpc.statd
|-rpcbind
|-rsyslogd---3*[{rsyslogd}]
|-ruby---{ruby}
|-sshd-+-3*[sshd---sshd---sftp-server]
| |-sshd---sshd---2*[sftp-server]
| |-sshd---sshd---bash---pstree
| `-sshd---sshd---bash---python---echo
|-systemd-logind
|-systemd-udevd
|-upstart-file-br
|-upstart-socket-
`-upstart-udev-br
注意这两者之间的区别
| `-sshd---sshd---bash---python-+-323*[echo]
| `-5*[python]
还有这个
| `-sshd---sshd---bash---python---echo
在一个cas中,流程似乎没有在完成后立即关闭
我已在4台不同的机器上测试了此问题:
- Ubuntu 14.04
- Centos 6
- Centos 7
watch-n0.1“pstree”
,查看流程是如何演变的
编辑:多亏了Glyph-answer,我明白了为什么会发生这种情况,但如何使其适应我的实际情况? 我正在使用Twisted开发的应用程序是一个基于Milter的SMTP过滤器,下面是它的工作原理(假设我们要检查电子邮件签名):
- 连接在端口25上打开
- milter协议获取所有电子邮件详细信息
- milter调用一个远程“模块”服务器,该服务器将通过
调用处理签名检查/usr/bin/openssl mime
- 模块将返回一个答案,指示签名是否有效
延迟信号量
放在哪里
我这里的问题是smtp连接也是不可知的,不知道其他可能的连接
在您看来,处理这种并行性的正确方法是什么?这里的问题与
任务.react
和reactor.run
之间的区别无关,而是与运行
和主
函数的实现之间细微但显著的区别有关
区别在于run
并行生成limit
进程,同时生成数千个打开的文件描述符,很容易突破系统的限制。但是,main
正在等待每个进程完全完成执行,甚至在启动下一个进程之前,这意味着它一次使用的进程不会超过4个或5个
原因是main
由inlineCallbacks
修饰,并生成每个getProcessOutputValue
Deferred
,这将暂停main
的执行,直到Deferred
完成
在实际应用中,这两种方法都不理想。您需要一些并行性,但不是无限的。Twisted附带了一些实用程序,例如,以促进有限的并行性,而不将所有内容限制为一次只运行一个任务。Jean-Paul Calderone在10年前写了一篇文章这就解释了如何使用这个
但是,为了证明该问题与任务无关。react
,下面是您示例的一个修改版本,它消除了运行
函数,并使用main
进行苹果对苹果的比较:
#!/usr/bin/env python
# -*- coding: utf-8 -*-
from progress.bar import IncrementalBar
from twisted.internet import defer
from twisted.internet import task
from twisted.internet import utils
from twisted.python import usage
class Options(usage.Options):
optFlags = [['reactor', 'r', 'Use reactor.run().'],
['task', 't', 'Use task.react().'],
['cwr', 'w', 'Use callWhenRunning().']]
optParameters = [['limit', 'l', 255, 'Number of file descriptors to open.'],
['cmd', 'c', 'echo Testing {i}...', 'Command to run.']]
@defer.inlineCallbacks
def main(reactor, opt):
d = defer.Deferred()
limit = int(opt['limit'])
cmd, args = opt['cmd'].split(' ', 1)
bar = IncrementalBar('Running {cmd}'.format(cmd=opt['cmd']), max=limit)
for i in range(0, limit):
try:
_args = args.format(i=i)
args = _args
except KeyError:
pass
yield utils.getProcessOutputAndValue('echo', [args])
bar.next()
bar.finish()
defer.returnValue(d.callback(True))
if __name__ == '__main__':
opt = Options()
opt.parseOptions()
if opt['reactor']:
from twisted.internet import reactor
task.deferLater(reactor, 0, main, reactor, opt)
reactor.run()
elif opt['task']:
from twisted.internet.task import react
react(main, [opt])
elif opt['cwr']:
from twisted.internet import reactor
reactor.callWhenRunning(main, reactor, opt)
reactor.run()
编辑,回答问题中的编辑:
由于您真正的问题在于传入连接,而不仅仅是
for
循环,而不是使用DeferredSemaphore
,因此您可能需要维护一个计数器,并利用从返回的对象或从返回的Deferred
的结果实现,当有太多的并发连接正在工作时,对其调用pauseProducing()
,当该工作完成时,对其调用resumeProducing()
。这就是任务的全部内容。react
执行的操作。将您的示例粘贴到Linux服务器上,我能够针对您提供的所有值成功运行您的示例,因此我不确定出了什么问题。可能是一些本地配置问题?我已经用pstree
运行了两个示例,当使用-r
开关时,我看到了300个python子流程,我将在上午向您粘贴一个详细的示例。我的印象是,进程一旦终止就会挂起,并导致/proc limit错误。我添加了pstree
图,并详细介绍了一些我的测试,这个问题已经在4台不同的机器和3个不同的操作系统上进行了测试。请注意,我更正了结果:失败的是-r开关python pyerr.py-l400-r
,而不是-tI开关,我无法重现您的fa