2009-12-02 13 views
15

Tôi có một trang web đó chạy với cấu hình sau:lỗi: không thể bắt đầu chủ đề mới

Django + mod-wsgi + apache

Trong một trong những yêu cầu của người dùng, tôi gửi một yêu cầu HTTP tới dịch vụ khác , và giải quyết điều này bằng thư viện httplib của python.

Nhưng đôi khi dịch vụ này không nhận được câu trả lời quá dài và thời gian chờ cho httplib không hoạt động. Vì vậy, tôi tạo chủ đề, trong chủ đề này tôi gửi yêu cầu đến dịch vụ và tham gia sau 20 giây (20 giây - là thời gian chờ yêu cầu). Đây là cách hoạt động:

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 

một cái gì đó như thế này ...

Và sử dụng nó bằng chức năng này:

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') 

Và tất cả hoạt động tốt, nhưng đôi khi tôi bắt đầu đánh bắt ngoại lệ này:

error: can't start new thread 

tại dòng bắt đầu chủ đề mới:

getting.start() 

và tiếp theo và dòng cuối cùng của traceback là

File "/usr/lib/python2.5/threading.py", line 440, in start 
    _start_new_thread(self.__bootstrap,()) 

Và câu trả lời là: Có gì xảy ra?

Cảm ơn tất cả và xin lỗi vì tiếng Anh thuần tuý của tôi. :)

Trả lời

5

Bạn đang bắt đầu nhiều chuỗi hơn là hệ thống của bạn có thể xử lý. Có một giới hạn về số lượng các luồng có thể được kích hoạt cho một tiến trình.

Ứng dụng của bạn đang bắt đầu chuỗi nhanh hơn các chuỗi đang chạy để hoàn tất. Nếu bạn cần phải bắt đầu nhiều chủ đề, bạn cần phải làm điều đó một cách kiểm soát hơn tôi sẽ đề nghị sử dụng một hồ bơi thread.

20

Lỗi "không thể bắt đầu chuỗi mới" gần như chắc chắn do thực tế là bạn đã có quá nhiều chuỗi chạy trong quá trình python của bạn và do giới hạn tài nguyên của một số yêu cầu tạo chuỗi mới bị từ chối.

Bạn có lẽ nên xem xét số lượng chủ đề bạn đang tạo; số lượng tối đa bạn sẽ có thể tạo sẽ được xác định bởi môi trường của bạn, nhưng nó phải ở mức tối thiểu là hàng trăm.

Có thể bạn nên nghĩ lại kiến ​​trúc của mình tại đây; nhìn thấy như thế này đang chạy không đồng bộ dù sao đi nữa, có lẽ bạn có thể sử dụng một nhóm các chủ đề để tìm nạp tài nguyên từ một trang web khác thay vì luôn khởi động một chuỗi cho mọi yêu cầu.

Một cải tiến khác cần xem xét là việc bạn sử dụng Thread.join và Thread.stop; điều này có thể được thực hiện tốt hơn bằng cách cung cấp một giá trị thời gian chờ cho constructor của HTTPSConnection.

+4

Lưu ý rằng số lượng chuỗi chạy có thể được hiển thị bằng cách sử dụng 'threading.active_count()'. – 101

+0

sugestion hữu ích, cảm ơn bạn! –

4

Tôi nghĩ rằng cách tốt nhất trong trường hợp của bạn là để thiết lập thời gian chờ ổ cắm thay vì chủ đề sinh sản:

h = httplib.HTTPSConnection(self.config['server'], 
          timeout=self.config['timeout']) 

Ngoài ra bạn có thể thiết lập thời gian chờ mặc định toàn cầu với socket.setdefaulttimeout() chức năng.

Cập nhật: Xem câu trả lời cho câu hỏi Is there any way to kill a Thread in Python? (có một vài thông tin khá) để hiểu lý do. Thread.__stop() không chấm dứt chuỗi, nhưng thay vì đặt cờ nội bộ để nó được coi là đã dừng.

+0

Nó có thể hữu ích cho tôi. Cảm ơn bạn. – Oduvan

3

Nếu bạn đang cố gắng đặt thời gian chờ tại sao bạn không sử dụng urllib2.

+0

urllib2 không có thời gian kết nối. – Oduvan

+1

urllib2 không có thời gian chờ. urllib2.urlopen (url [, dữ liệu] [, timeout]) Prashanth

+1

đối số 'timeout' mới trong Python 2.6 –

4

Tôi viết lại hoàn toàn mã từ httplib đến 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() 

điều gì đó tương tự.

Và tôi đã thử nghiệm ngay bây giờ. Cảm ơn tất cả các bạn đã giúp đỡ.