4

我正在编写一些使用 mechanize 从另一个网站获取数据的 python 代码。由于网站的复杂性,代码需要 10-30 秒才能完成。它必须通过几页之类的方式工作。

我计划让这段代码被相当频繁地调用。我想知道在不造成巨大服务器负载的情况下实现这样的事情的最佳方法。由于我对 python 还很陌生,我不确定该语言是如何工作的。

如果代码正在处理一个请求,而另一个用户调用了该代码,那么该代码的两个实例可以同时运行吗?有没有更好的方法来实现这样的事情?

我想以一种可以完成繁重任务的方式来设计它,而不会对服务器造成太大负担。

4

3 回答 3

1

我的数据抓取脚本都使用缓存来最小化服务器上​​的负载。请务必使用 HTTP 工具,例如“If-Modified-Since”、“If-None-Match”和“Accept-Encoding: gzip”。

还可以考虑使用多处理模块,以便您可以并行运行请求。

这是我的下载器脚本的摘录:

def urlretrieve(url, filename, cache, lock=threading.Lock()):
    'Read contents of an open url, use etags and decompress if needed'    

    request = urllib2.Request(url)
    request.add_header('Accept-Encoding', 'gzip')
    with lock:
        if ('etag ' + url) in cache:
            request.add_header('If-None-Match', cache['etag ' + url])
        if ('date ' + url) in cache:
            request.add_header('If-Modified-Since', cache['date ' + url])

    try:
        u = urllib2.urlopen(request)
    except urllib2.HTTPError as e:
        return Response(e.code, e.msg, False, False)
    content = u.read()
    u.close()

    compressed = u.info().getheader('Content-Encoding') == 'gzip'
    if compressed:
        content = gzip.GzipFile(fileobj=StringIO.StringIO(content), mode='rb').read()

    written = writefile(filename, content) 

    with lock:
        etag = u.info().getheader('Etag')
        if etag:
            cache['etag ' + url] = etag
        timestamp = u.info().getheader('Date')
        if timestamp:
            cache['date ' + url] = timestamp

    return Response(u.code, u.msg, compressed, written)

缓存是shelve的一个实例,一个持久字典。

对下载器的调用与多处理池实例上的 imap_unordered() 并行化。

于 2012-08-01T15:39:46.533 回答
0

您一次可以运行多个 python 进程。至于导致服务器上的过度负载,只能通过确保在任何给定时间只有一个实例运行或其他数量的进程(比如两个)来缓解。为此,您可以查看使用锁定文件或某种系统标志、互斥锁等...

但是,限制过度使用的最佳方法是限制并发运行的任务数。

于 2012-08-01T15:35:06.133 回答
0

基本答案是“您可以运行任意数量的程序实例,只要它们不共享关键资源(如数据库)”。

在现实世界中,您经常需要使用“多处理模块”并正确设计您的应用程序以处理并发并避免损坏状态或死锁。

顺便说一句,多进程应用程序的设计超出了 StackOverflow 上一个简单问题的范围......

于 2012-08-01T15:37:15.933 回答