先日、ここでPython Webスパイダーを作成しました。タスクは一般に単純ですが、負荷が大きいため、実際には5つのスパイダー(5つのスレッド)を実行する必要があります。一般的に、ソリューションは興味深いものでした。標準のPython libs
socket 、
httplib 、
urllib2に登る機会があり
urllib2 (興味があれば、この経験を説明できます)。
ここでお話ししたいのは、作成されたオブジェクトに従わないという中毒が、ガベージコレクション言語で教えられることです。 スパイダーを監視しているときに、
CLOSE_WAIT状態の多くのソケットがシステムにハングしていることに気付きました。 これは、サーバー側でソケットが既に閉じられているが、まだメモリに残っているためです。 つまり、大まかに言って、
closeメソッドはソケットで呼び出されず、オブジェクト自体はまだメモリのどこかにハングしています。
urllib2、
urllib2 、および
socketを調べた
urllib2 、それらの作業のメカニズムに関する次の情報を受け取りました。
- ページをロードするには、
urllib2.OpenDirector.open呼び出しurllib2.OpenDirector.open 。 urllib2.HTTPHandler.openメソッドを呼び出し、 urllib2.HTTPHandler.openを呼び出しますurllib2.AbstractHTTPHandler.do_open- 通信タスクを直接実行するために、
httplib.HTTPConnectionにタイプdo_openのhオブジェクトが作成されます。 重要なポイントdo_openを終了すると、このオブジェクトは消えます! hはソケットを生成して開き、 self.sock属性に保存します。hは、サーバーに要求を送信します。do_openはサーバーにhを要求し、タイプhttplib.HTTPResponse rオブジェクトをhttplib.HTTPResponseます。- このオブジェクトは、
h.sockソケットに基づいて作成されると、アプリケーションがデータの読み取りに使用するh.sock.makefileメソッドを使用してh.sock.makefileファイルオブジェクトを作成します。 繰り返しますが、重要な点は、コンストラクターに渡されるソケットオブジェクトはどこにも保存されないということです。 do_openは、受信したHTTPResponseをサービスオブジェクトにラップし、アプリケーションに返します。- アプリケーションはデータを読み取り、
HTTPResponseを閉じます。
したがって、ソケットオブジェクト自体(実際のソケットのラッパー)はもう存在しない可能性があります。 少なくともどこにもリンクがありません。 しかし、ソケット自体はまだ残っています! 誰も彼を近くに電話しませんでした! 要するに、これまでのところ、1つのオプションだけが思い浮かびました。読み取りが完了したら、次の形式の「わかりやすい」コードを使用して、サービスリンクのかかとを通してソケットを手動で閉じます。
tf.fp._sock.fp._sock.close()
ここで、
tfはurllib2.openから取得したリンクです。 これはパイです:)これは、2.5に戻ったところであります。 2.4では、さらに悪いバグがいくつかあります。 この振る舞いを正しく打ち破る方法についてのヒントを喜んでいます。