Python 错误:can';不要开始新的线程

Python 错误:can';不要开始新的线程,python,django,multithreading,mod-wsgi,httplib,Python,Django,Multithreading,Mod Wsgi,Httplib,我有一个使用以下配置运行的站点: Django+mod wsgi+apache 在用户的一个请求中,我向另一个服务发送了另一个HTTP请求,并通过python的httplib库解决了这个问题 但有时候这个服务并没有得到太长的答案,httplib的超时也不起作用。所以我创建了一个线程,在这个线程中我向服务发送请求,并在20秒后加入它(20秒-是请求超时)。这就是它的工作原理: class HttpGetTimeOut(threading.Thread): def __init__(self

我有一个使用以下配置运行的站点:

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, ())
答案是:发生了什么


谢谢大家,对不起我的纯正英语。:)

启动的线程数量超出了系统的处理能力。对于一个进程,可以活动的线程数是有限制的

应用程序启动线程的速度比线程运行到完成的速度快。如果需要启动多个线程,则需要以更可控的方式启动。我建议使用线程池。

几乎肯定会出现“无法启动新线程”错误,因为python进程中已经运行了太多线程,由于某种资源限制,创建新线程的请求被拒绝

您可能应该查看正在创建的线程数量;您可以创建的最大数量将由您的环境决定,但至少应该是数百个

在这里重新思考您的架构可能是个好主意;鉴于这是异步运行的,也许您可以使用一个线程池从另一个站点获取资源,而不是总是为每个请求启动一个线程


另一个需要考虑的改进是线程的使用。通过向HTTPSConnection的构造函数提供超时值可能会更好地实现这一点。

我认为在您的情况下,最好的方法是设置套接字超时,而不是生成线程:

h = httplib.HTTPSConnection(self.config['server'], 
                            timeout=self.config['timeout'])
还可以使用函数设置全局默认超时


更新:请参阅问题的答案(有几项内容丰富),了解原因<代码>线程。_stop()不终止线程,而是设置内部标志,使其被视为已停止。

如果要设置超时,为什么不使用。

我完全将代码从httplib重写为pycurl

c = pycurl.Curl()
c.setopt(pycurl.FOLLOWLOCATION, 1)
c.setopt(pycurl.MAXREDIRS, 5)
c.setopt(pycurl.CONNECTTIMEOUT, CONNECTION_TIMEOUT)
c.setopt(pycurl.TIMEOUT, COOPERATION_TIMEOUT)
c.setopt(pycurl.NOSIGNAL, 1)
c.setopt(pycurl.POST, 1)
c.setopt(pycurl.SSL_VERIFYHOST, 0)
c.setopt(pycurl.SSL_VERIFYPEER, 0)
c.setopt(pycurl.URL, "https://"+server+path)
c.setopt(pycurl.POSTFIELDS,sended_data)

b = StringIO.StringIO()
c.setopt(pycurl.WRITEFUNCTION, b.write)

c.perform()
差不多吧


我现在正在测试它。谢谢大家的帮助。

在我的例子中,我在启动新线程之前添加了此代码。它为应用程序提供了运行线程等待的最大限制

while threading.active_count()>150 :
    time.sleep(5)
getting.start()
注意:这不是一个好的解决方案,但我必须找到一个解决方法 这个问题对我来说很有效


如果您使用的是ThreadPoolExecutor,则问题可能是您的最大工作线程数高于操作系统允许的线程数


执行器似乎将最后执行的线程的信息保存在进程表中,即使这些线程已经完成。这意味着,当您的应用程序运行很长时间后,它最终将在进程表中注册与ThreadPoolExecutor相同数量的线程。max_workers

我在类似的情况下运行,但我的进程需要运行大量线程来处理大量连接

我使用命令计算线程数:

ps-fLu用户| wc-l

它显示了4098

我切换到用户并查看系统限制:

sudo-u myuser-s/bin/bash

ulimit-u

得到4096的答复

因此,我编辑了/etc/security/limits.d/30-myuser.conf并添加了以下行:

myuser硬盘nproc 16384

myuser软nproc 16384

重新启动服务,现在它正在运行7017个线程


另外,我有一个32核的服务器,我正在使用此配置处理18k的同时连接。

urllib2没有连接超时。urllib2有超时。urlib2.urlopen(url[,data][,timeout])
timeout
参数在Python2.6中是新的,它对我很有用。谢谢。请注意,可以使用
threading.active\u count()
显示正在运行的线程数。您找到一些解决方法了吗?