35

次の構成で実行されるサイトがあります。

Django + mod-wsgi + Apache

ユーザーのリクエストの 1 つで、別のサービスに別の 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, ())

答えは次のとおりです。

すべてに感謝し、私の純粋な英語で申し訳ありません。:)

4

8 に答える 8

41

「新しいスレッドを開始できません」というエラーは、ほとんどの場合、Python プロセス内で既に実行されているスレッドが多すぎるためであり、何らかのリソース制限により、新しいスレッドを作成する要求が拒否されます。

おそらく、作成しているスレッドの数を確認する必要があります。作成できる最大数は環境によって決まりますが、少なくとも数百のオーダーである必要があります。

ここでアーキテクチャを再考することをお勧めします。これはとにかく非同期で実行されているため、すべてのリクエストに対して常にスレッドを開始するのではなく、スレッドのプールを使用して別のサイトからリソースをフェッチすることができます。

考慮すべきもう 1 つの改善点は、Thread.join と Thread.stop の使用です。これはおそらく、HTTPSConnection のコンストラクターにタイムアウト値を指定することで実現できます。

于 2009-12-02T18:56:42.117 に答える
12

システムで処理できるよりも多くのスレッドを開始しています。1 つのプロセスでアクティブにできるスレッドの数には制限があります。

アプリケーションは、スレッドが完了するまで実行される速度よりも速くスレッドを開始しています。多くのスレッドを開始する必要がある場合は、より制御された方法で実行する必要があります。スレッド プールを使用することをお勧めします。

于 2009-12-02T18:56:01.170 に答える
6

あなたの場合、スレッドを生成する代わりにソケットタイムアウトを設定するのが最善の方法だと思います:

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

また、関数を使用してグローバルなデフォルト タイムアウトを設定することもできますsocket.setdefaulttimeout()

更新: Python でスレッドを強制終了する方法はありますか? への回答を参照してください。その理由を理解するための質問 (非常に有益な質問がいくつかあります)。Thread.__stop()スレッドを終了しませんが、既に停止していると見なされるように内部フラグを設定します。

于 2009-12-03T11:03:21.510 に答える
5

コードを 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()

そんな感じ。

そして、私は今それをテストしています。助けてくれてありがとう。

于 2009-12-03T18:46:52.053 に答える
4

タイムアウトを設定する場合は、なぜurllib2を使用しないのですか。

于 2009-12-03T15:57:48.597 に答える
2

一部のファイルをある形式から別の形式にコピーして変換するためだけに、自分のマシンで python スクリプトを実行しています。実行中のスレッドの数を最大にして、できるだけ早く終了させたいと考えています。

注: 特定のマシンでのクイック スクリプトに使用していない場合、アーキテクチャの観点からは適切な回避策ではありません。

私の場合、エラーが発生する前にマシンが実行できる実行中のスレッドの最大数を確認しました。150

新しいスレッドを開始する前に、このコードを追加しました。これは、実行中のスレッドの最大制限に達したかどうかを確認し、アプリは実行中のスレッドの一部が終了するまで待機してから、新しいスレッドを開始します

while threading.active_count()>150 :
    time.sleep(5)
mythread.start()
于 2019-03-03T12:34:27.723 に答える