错误:无法启动新线程
我有一个网站,运行的配置是:
Django + mod-wsgi + apache
在用户发起请求时,我会向另一个服务发送HTTP请求,使用的是Python的httplib库来处理这个请求。
但是有时候这个服务的响应时间太长,导致httplib的超时设置没有效果。所以我创建了一个线程,在这个线程里发送请求,并在20秒后结束这个线程(20秒是我设定的请求超时时间)。这是它的工作方式:
class HttpGetTimeOut(threading.Thread):
def __init__(self,**kwargs):
self.config = kwargs
self.resp_data = None
self.exception = None
super(HttpGetTimeOut,self).__init__()
def run(self):
h = httplib.HTTPSConnection(self.config['server'])
h.connect()
sended_data = self.config['sended_data']
h.putrequest("POST", self.config['path'])
h.putheader("Content-Length", str(len(sended_data)))
h.putheader("Content-Type", 'text/xml; charset="utf-8"')
if 'base_auth' in self.config:
base64string = base64.encodestring('%s:%s' % self.config['base_auth'])[:-1]
h.putheader("Authorization", "Basic %s" % base64string)
h.endheaders()
try:
h.send(sended_data)
self.resp_data = h.getresponse()
except httplib.HTTPException,e:
self.exception = e
except Exception,e:
self.exception = e
大概是这样的……
然后通过这个函数来使用它:
getting = HttpGetTimeOut(**req_config)
getting.start()
getting.join(COOPERATION_TIMEOUT)
if getting.isAlive(): #maybe need some block
getting._Thread__stop()
raise ValueError('Timeout')
else:
if getting.resp_data:
r = getting.resp_data
else:
if getting.exception:
raise ValueError('REquest Exception')
else:
raise ValueError('Undefined exception')
一切都运行得很好,但有时候我会遇到这个异常:
error: can't start new thread
在启动新线程的那一行:
getting.start()
而追踪信息的最后一行是:
File "/usr/lib/python2.5/threading.py", line 440, in start
_start_new_thread(self.__bootstrap, ())
那么问题是:发生了什么?
谢谢大家,抱歉我的英语不好。:)
10 个回答
我之前遇到过类似的情况,但我的程序需要很多线程来处理大量的连接。
我用这个命令来统计线程的数量:
ps -fLu user | wc -l
结果显示有4098个线程。
我切换到那个用户,查看系统的限制:
sudo -u myuser -s /bin/bash
ulimit -u
得到的回应是4096。
于是,我编辑了这个文件 /etc/security/limits.d/30-myuser.conf,添加了以下内容:
myuser hard nproc 16384
myuser soft nproc 16384
重启了服务,现在它运行着7017个线程。
顺便说一下,我的服务器有32个核心,使用这个配置可以处理18000个同时连接。
你启动的线程数量超过了你的系统能处理的范围。每个程序能同时活动的线程数量是有限的。
你的应用程序启动线程的速度比这些线程完成工作的速度要快。如果你需要启动很多线程,建议你采取更有控制的方法,比如使用线程池。
“无法启动新线程”的错误几乎肯定是因为你在 Python 程序中已经有太多线程在运行了,由于某种资源限制,系统拒绝了你创建新线程的请求。
你可能需要看看你创建了多少个线程;你能创建的最大线程数是由你的环境决定的,但至少应该能达到几百个。
在这里重新考虑一下你的设计可能是个好主意;既然这个程序是异步运行的,也许你可以使用一个线程池来从其他网站获取资源,而不是每次请求都启动一个新线程。
另一个可以改进的地方是你对 Thread.join 和 Thread.stop 的使用;这可能更好地通过给 HTTPSConnection 的构造函数提供一个超时时间来实现。