1

これが問題のコード (非常に単純なクローラー) です。ファイルは URL のリストで、通常は 1000 を超えています。

import sys, gevent
from gevent import monkey
from gevent.pool import Pool
import httplib, socket
from urlparse import urlparse
from time import time

pool = Pool(100)

monkey.patch_all(thread=False)

count = 0
size = 0
failures = 0

global_timeout = 5
socket.setdefaulttimeout(global_timeout)

def process(ourl, mode = 'GET'):
    global size, failures, global_timeout, count
    try:
        url = urlparse(ourl)
        start = time()
        conn = httplib.HTTPConnection(url.netloc, timeout = global_timeout)
        conn.request(mode, ourl)
        res = conn.getresponse()
        req = res.read()
        end = time()
        bytes = len(req)
        took = end - start
        print mode, ourl, bytes, took
        size = size + len(req)
        count += 1
    except Exception, e:
        failures += 1

start = time()

gevent.core.dns_init()
print "spawning..."
for url in open('domains'):
    pool.spawn(process, url.rstrip())
print "done...joining..."
pool.join()
print "complete"

end = time()
took = end - start
rate = size / took
print "It took %.2f seconds to process %d urls." % (took, count)
print rate, " bytes/sec"
print rate/1024, " KB/sec"
print rate/1048576, " MB/sec"

print "--- summary ---"
print "total:", count, "failures:", failures

プールサイズを変更すると、非常に多くの異なる速度のバリエーションが得られます: -

pool = Pool(100)

その場で理想的なプールサイズを計算するアルゴリズムを書くことを考えていましたが、飛び込むのではなく、見落としているものがあるかどうか知りたいですか?

4

1 に答える 1

5

並列処理は、CPUバウンドまたはIOバウンドのいずれかになります。コードの性質からすると、プールのサイズが小さいとIOバウンドになるように見えます。具体的には、インターフェイスの帯域幅と、システムが維持できる同時に開いているソケットの数によって制限されます(ここで、使用可能なソケットが何度も不足しているWindowsのバージョンを考えてみてください)。プールサイズを大きくすると、プロセスがCPUバウンドに転じ始める可能性があります(特に、ここに表示されていないデータ処理が多い場合)。プールサイズを最適な値に保つには、これらすべての変数の使用状況(開いているソケットの数、プロセスによる帯域幅使用率、CPU使用率など)を監視する必要があります。クローラーを実行しているときにメトリックをプロファイリングしてプールサイズに必要な調整を行うことでこれを手動で行うか、これを自動化してみることができます。Python内からそのようなことが可能かどうかは別問題です。

于 2012-08-15T15:30:27.130 に答える