您好, 欢迎来到 !    登录 | 注册 | | 设为首页 | 收藏本站

如何在python中使用urllib2加快获取页面的速度?

如何在python中使用urllib2加快获取页面的速度?

:我正在扩大答案,以包括一个更完善的示例。我在这文章中发现了很多关于线程与异步I / O的敌意和错误信息。因此,我还添加了更多论点来驳斥某些无效的主张。我希望这将帮助人们为正确的工作选择正确的工具。

这是3天前提出的问题的答案。

Python urllib2.open运行缓慢,需要一种更好的方法来读取多个URL-堆栈溢出 Python urllib2.urlopen()运行缓慢,需要一种更好的方法来读取多个URL

我正在完善代码显示如何使用线程并行获取多个网页。

import time
import threading
import Queue

# utility - spawn a thread to execute target for each args
def run_parallel_in_threads(target, args_list):
    result = Queue.Queue()
    # wrapper to collect return value in a Queue
    def task_wrapper(*args):
        result.put(target(*args))
    threads = [threading.Thread(target=task_wrapper, args=args) for args in args_list]
    for t in threads:
        t.start()
    for t in threads:
        t.join()
    return result

def dummy_task(n):
    for i in xrange(n):
        time.sleep(0.1)
    return n

# below is the application code
urls = [
    ('http://www.google.com/',),
    ('http://www.lycos.com/',),
    ('http://www.bing.com/',),
    ('http://www.altavista.com/',),
    ('http://achewood.com/',),
]

def fetch(url):
    return urllib2.urlopen(url).read()

run_parallel_in_threads(fetch, urls)

如您所见,特定于应用程序的代码只有3行,如果您比较积极,可以将其折叠为1行。我认为没有人能证明他们的主张是复杂且不可维持的。

不幸的是,这里发布的大多数其他线程代码都有一些缺陷。他们中的许多人都进行主动轮询以等待代码完成。join()是同步代码的更好方法。我认为到目前为止,此代码已对所有线程示例进行了改进。

如果您所有的URL都指向同一服务器,那么WoLpH关于使用保持活动连接的建议可能会非常有用。

亚伦·加拉格尔(Aaron Gallagher)是twisted框架的狂热者,他对任何建议使用线程的人都怀有敌意。不幸的是,他的许多说法都是错误的信息。例如,他说“ -1表示线程建议。这是IO绑定的;线程在这里无用。” 这与证据相反,因为我和Nick T都已经证明了使用线程的速度提高。实际上,使用Python的线程可以最大程度地提高I / O绑定的应用程序的收益(而cpu绑定的应用程序则没有收益)。Aaron对线程的误导性批评表明,他对并行编程感到困惑。

我很清楚与使用线程,python,异步I / O等进行并行编程有关的问题。每个工具都有其优缺点。对于每种情况,都有一个适当的工具。我不反对扭曲(尽管我自己还没有部署)。但是我不相信我们可以断定在所有情况下线程都是错误的,而扭曲是良好的。

例如,如果OP的要求是并行获取10,000个网站,则异步I / O是可取的。线程是不适当的(除非使用无堆栈Python)。

亚伦对线程的反对大多是概括。他未能意识到这是一项琐碎的并行化任务。每个任务都是独立的,并且不共享资源。因此,他的大部分攻击都不适用。

鉴于我的代码没有外部依赖关系,因此我将其称为用于正确工作的正确工具。

我认为大多数人都会同意,此任务的性能在很大程度上取决于网络代码和外部服务器,而平台代码性能在这些方面可以忽略不计。但是Aaron的基准测试显示,与线程代码相比,速度提高了50%。我认为有必要对这种明显的速度提高做出反应。

在尼克的代码中,有一个明显的缺陷导致效率低下。但是您如何解释我的代码比233ms的速度提高呢?我认为即使是扭曲的粉丝也不会做出结论,将其归因于扭曲的效率。毕竟,系统代码之外还有大量变量,例如远程服务器的性能,网络,缓存以及urllib2和扭曲的Web客户端之间的差异实现等。

为了确保Python的线程不会导致大量的低效率,我做了一个快速基准测试,先生成5个线程,然后生成500个线程。我很舒服地说生成5个线程的开销可以忽略不计,并且不能解释233ms的速度差异。

In [274]: %time run_parallel_in_threads(dummy_task, [(0,)]*5)
cpu times: user 0.00 s, sys: 0.00 s, total: 0.00 s
Wall time: 0.00 s
Out[275]: <Queue.Queue instance at 0x038B2878>

In [276]: %time run_parallel_in_threads(dummy_task, [(0,)]*500)
cpu times: user 0.16 s, sys: 0.00 s, total: 0.16 s
Wall time: 0.16 s

In [278]: %time run_parallel_in_threads(dummy_task, [(10,)]*500)
cpu times: user 1.13 s, sys: 0.00 s, total: 1.13 s
Wall time: 1.13 s       <<<<<<<< This means 0.13s of overhead

在我的并行读取中进行的进一步测试显示,在17次运行中响应时间存在巨大差异。(不幸的是,我没有费力去验证Aaron的代码)。

0.75 s
0.38 s
0.59 s
0.38 s
0.62 s
1.50 s
0.49 s
0.36 s
0.95 s
0.43 s
0.61 s
0.81 s
0.46 s
1.21 s
2.87 s
1.04 s
1.72 s

我的测试不支持亚伦的结论,即线程始终比异步I / O慢很多。给定涉及的变量数量,我不得不说这不是衡量异步I / O与线程之间系统性能差异的有效测试。

python 2022/1/1 18:47:58 有314人围观

撰写回答


你尚未登录,登录后可以

和开发者交流问题的细节

关注并接收问题和回答的更新提醒

参与内容的编辑和改进,让解决方法与时俱进

请先登录

推荐问题


联系我
置顶