まず、キャンセルする前に、各ページのすべてまたはほとんどを OS バッファー、NIC、ルーター、または ISP に既に取得している可能性があることに注意してください。また、コストがかかります。接続を早期に閉じると、接続を再利用できなくなります。recv
早めにキャンセルしたい場合は、一度に小さくする必要があります。等
読み取る必要があると思われるバイト数の大まかな考えがあり (時々少し下に行くよりも、少し多くする方が良い)、サーバーが HTTP 範囲要求を処理する場合は、代わりにそれを試してください。ファイル全体を要求してから、ソケットを早期に閉じます。
ただし、ソケットを早期に閉じる方法を知りたい場合は、次のようにします。
urllib2.urlopen
、requests
、およびその他のほとんどの高レベル ライブラリは、ファイル全体を読み取りたいという考えに基づいて設計されています。入ってくるデータをバッファリングして、高レベルのファイルのようなインターフェイスを提供します。その上、API がブロックされています。どちらもあなたが望むものではありません。バイトが入ってくるとできるだけ早く取得したいし、ソケットを閉じるときは、できるだけ早くそれを取得したいと考えていますrecv
。
そのため、Python ラッパーの 1 つを使用することを検討することをお勧めしlibcurl
ます。これにより、パワー/柔軟性と使いやすさのバランスがかなり取れます。たとえば、次の場合pycurl
:
import pycurl
buf = ''
def callback(newbuf):
global buf
buf += newbuf
if '<div style="float: right; margin-left: 8px;">' in buf:
return 0
return len(newbuf)
c = pycurl.Curl()
c.setopt(c.URL, 'http://curl.haxx.se/dev/')
c.setopt(c.WRITEFUNCTION, callback)
try:
c.perform()
except Exception as e:
print(e)
c.close()
print len(buf)
結局のところ、これはそのテストで 12259/12259 バイトを読み取ることになります。しかし、最初の 2650 バイトの文字列に変更すると、2650/12259 バイトしか読み取れません。そして、Wireshark と instrument を起動するとrecv
、次のパケットが NIC に到着したにもかかわらず、実際にはそれを読み取っていないことがわかります。2650 バイトを受信した直後にソケットを閉じました。それで、それはいくらかの時間を節約するかもしれません…おそらくそれほど多くはありません. さらに重要なことは、13MB の画像ファイルを投げて 1MB で停止しようとしても、数 KB しか追加されず、ほとんどの画像がまだルーターに届いていないことです (ただし、すべての画像ファイルがある可能性があります)サーバーに優しくすることを気にしている場合は、サーバーを離れてください)、間違いなく時間を節約できます。
もちろん、典型的なフォーラム ページは 13MB よりも 12KB にかなり近いです。(たとえば、このページは、とりとめのない作業を行った後でも、48KB をはるかに下回っていました。) しかし、おそらく、あなたは通常とは異なるフォーラムを扱っているのではないでしょうか。
ページが非常に大きい場合は、コードを変更して、buf[-len(needle):] + newbuf
毎回バッファー全体ではなくチェックのみを行うことができます。13MB の画像でも、全体を何度も検索しても合計実行時間はそれほど増えませんでしたが、 CPU 使用率が 1% から 9% に上昇しました…</p>
最後に 1 つ: たとえば 500 ページを読んでいる場合、それらを同時に (たとえば一度に 8 ページずつ) 行うと、各ページを早めにキャンセルするよりもはるかに多くの時間を節約できます。両方を一緒に使用することは、単独で使用するよりも優れている可能性があります。これは、これを行うことに対する議論ではありません。(同時実行を処理receiver-multi.py
させたい場合は、サンプルを参照curl
してください... または、子プロセスのプールを使用するmultiprocessing
か、使用するだけです。)concurrent.futures