V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
推荐学习书目
Learn Python the Hard Way
Python Sites
PyPI - Python Package Index
http://diveintopython.org/toc/index.html
Pocoo
值得关注的项目
PyPy
Celery
Jinja2
Read the Docs
gevent
pyenv
virtualenv
Stackless Python
Beautiful Soup
结巴中文分词
Green Unicorn
Sentry
Shovel
Pyflakes
pytest
Python 编程
pep8 Checker
Styles
PEP 8
Google Python Style Guide
Code Style from The Hitchhiker's Guide
cyrbuzz
V2EX  ›  Python

requests 多线程与无法访问的 url 问题。

  •  
  •   cyrbuzz ·
    HuberTRoy · 2017-04-03 12:07:24 +08:00 · 7272 次点击
    这是一个创建于 2573 天前的主题,其中的信息可能已经有所发展或是发生改变。

    使用 requests 时,发现一个问题。

    一个基本的请求。

    requests.get('http://www.xxx.com', headers=headers)
    

    当用多线程时: 效率会明显提高,但是如果这个 url 是打不开的,那多线程会变得与单线程一样,会卡在那个不能打开的 url 上一直等待到报错。 timeout 参数只对可以打开的 url 有效果。

    多线程:

    def getHtml(url):
        try:
            requests.get(url)
            print(url)
        except:
            print("wrong: {0}".format(url))
    

    0 (仅测试。)

    import threading
    for url in urls:
        worker = threading.Thread(target=getHtml, args=(url,))
        worker.start()
    

    问题依旧。

    1 使用封装的线程池。

    from concurrent.futures import ThreadPoolExecutor
    
    with ThreadPoolExecutor(max_workers=10) as t:
        for url in urls:
            t.submit(getHtml, url)
    

    查到用 map 方法可以设置 timeout ,不过设置后发现没用。。

    with ThreadPoolExecutor(max_workers=10) as t:
        t.map(getHtml, urls, timeout=1)
    

    2 使用 multiprocessing.dummy 的线程池。

    发现一篇用这个库的文章。 https://segmentfault.com/a/1190000000382873

    from multiprocessing.dummy import Pool as ThraedPool
    pool = ThreadPool(10)
    pool.map(getHtml, urls)
    pool.close()
    pool.join()
    
    

    还是一样。遇到打不开的网址都会等待。

    测试数据:

    urls = [
    'http://huahao917.com',
    'http://huanreshebei.net',
    'http://hyjsbj.com',
    'http://hzjfwj.com',
    'http://kitairu.net',
    'http://jy-qj.com.cn',
    'http://luosi580.com',
    'http://lyljbj.com',
    'http://psxti.com',
    'http://pt-ti.cn']
    

    其中 http://jy-qj.com.cnhttp://hzjfwj.com 是无法访问的。

    urllib.urlrequest.urlopen 与 requests 一样会等待,有什么办法可以不在那个无法访问的网址上等待?

    还是我的多线程姿势用错了?望指教。

    第 1 条附言  ·  2017-04-03 12:44:52 +08:00

    python 3.4.1 64位 requests2.9.1 windows 7 64位。

    20 条回复    2017-04-05 20:43:45 +08:00
    bazingaterry
        1
    bazingaterry  
       2017-04-03 12:23:24 +08:00 via iPhone
    pool.join() 的意思不就是等待所有线程结束吗?
    xiaoyu233
        2
    xiaoyu233  
       2017-04-03 12:28:29 +08:00
    [xiaoyu@MacBook-Pro:~]$ ping hzjfwj.com
    PING hzjfwj.com (210.209.82.181): 56 data bytes
    Request timeout for icmp_seq 0
    Request timeout for icmp_seq 1
    Request timeout for icmp_seq 2
    ^C
    --- hzjfwj.com ping statistics ---
    4 packets transmitted, 0 packets received, 100.0% packet loss
    [xiaoyu@MacBook-Pro:~]$ ping jy-qj.com.cn
    ping: cannot resolve jy-qj.com.cn: Unknown host

    你是 requests hzjfwj.com 的时候卡住了吧,设置 response = requests.get('http://hzjfwj.com', timeout=5)超时就好了
    cyrbuzz
        3
    cyrbuzz  
    OP
       2017-04-03 12:29:47 +08:00
    @bazingaterry
    pool.join()是等待所有线程结束不过运行到不能打开的网址时会一直等待那一个线程。
    cyrbuzz
        4
    cyrbuzz  
    OP
       2017-04-03 12:30:20 +08:00
    @xiaoyu233
    http://jy-qj.com.cn 这个网址设置 timeout 无效。。
    xiaoyu233
        5
    xiaoyu233  
       2017-04-03 12:34:42 +08:00
    @cyrbuzz 无效是什么意思,我运行了没发现问题啊
    cyrbuzz
        6
    cyrbuzz  
    OP
       2017-04-03 12:36:41 +08:00
    @xiaoyu233
    requests.get('http://jy-qj.com.cn', timeout=1.5)
    还是会等待老长时间然后报这个错
    requests.exceptions.ConnectionError: HTTPConnectionPool(host='jy-qj.com.cn', port=80): Max retries exceeded with url: / (Caused by NewConnectionError('<requests.packages.urllib3.connection.HTTPConnection object at 0x00000000032ED358>: Failed to establish a new connection: [Errno 11004] getaddrinfo failed',))

    python3.4.1 requests2.9.1
    xiaoyu233
        7
    xiaoyu233  
       2017-04-03 12:46:01 +08:00
    @cyrbuzz http://jy-qj.com.cn 这个不管你设置多少都是秒报错啊,他域名都没解析,更新下 requests 版本吧,我测试没出现你这情况
    wisefree
        8
    wisefree  
       2017-04-03 12:49:58 +08:00 via Android
    @xiaoyu233 这个是正解,在 requests 设置 timeout
    xiaoyu233
        9
    xiaoyu233  
       2017-04-03 12:58:36 +08:00   ❤️ 1
    @cyrbuzz 或者 requests 前先 ping 如果 Unknown host 直接 break =,=||
    cyrbuzz
        10
    cyrbuzz  
    OP
       2017-04-03 13:12:20 +08:00
    @xiaoyu233 更新成 2.13.0 ,还是要等老长时间。在虚拟机 32 位 win7 32 位 python 测试等待的时间少些,没达到秒报错。
    先用 ping 检测下了。
    xiaoyu233
        11
    xiaoyu233  
       2017-04-03 13:13:26 +08:00
    @cyrbuzz 我不是 win 系统😊
    cyrbuzz
        12
    cyrbuzz  
    OP
       2017-04-03 13:16:17 +08:00
    @xiaoyu233 不过还有个问题,既然是多线程,那就让哪一个线程等待就是了,为什么会卡在一个线程上呢。。
    xiaoyu233
        13
    xiaoyu233  
       2017-04-03 13:28:14 +08:00
    @cyrbuzz 不知道,好像没卡在一个线程上啊,只是程序好像要等待所有线程结束,你可以用 BoundedSemaphore 来控制阻塞
    a87150
        14
    a87150  
       2017-04-03 13:31:32 +08:00
    我试怎么没问题?
    cyrbuzz
        15
    cyrbuzz  
    OP
       2017-04-03 13:50:28 +08:00
    @xiaoyu233
    @a87150
    你们的 python 都是什么版本。我更新下 python 看看是不是 python 的问题。
    我这边只要不是无法解析的网址都是正常运行,一有无法解析的就卡主一会。。
    xiaoyu233
        16
    xiaoyu233  
       2017-04-03 13:54:00 +08:00
    Python 2.7.11 |Anaconda 2.5.0 (x86_64)| (default, Dec 6 2015, 18:57:58)
    [GCC 4.2.1 (Apple Inc. build 5577)] on darwin
    botman
        17
    botman  
       2017-04-04 11:34:07 +08:00 via Android
    requests timeout + 线程 timeout, 用 requests 有时确实会发生永久阻塞不解析的问题 原因比较难找 多半可能和系统环境有关系 保险的方式还是给每个线程都加 timeout
    cyrbuzz
        18
    cyrbuzz  
    OP
       2017-04-04 17:25:31 +08:00
    @botman 抛开自己写,有没有可以自带线程超时的包,
    from concurrent.futures import ThreadPoolExecutor
    一般用这个线程池,他的 map 方法有一个 timeout ,不过尝试后发现没效果。
    botman
        19
    botman  
       2017-04-04 21:56:10 +08:00   ❤️ 1
    @cyrbuzz python 标准库 threading 的 join 自带 timeout 用起来很简单的,还有就是看看 gevent 这个是用协程实现的并发框架非常的好用, timeout 也有好几种实现,具体细节请自行搜索相关 sample 和文档。
    cyrbuzz
        20
    cyrbuzz  
    OP
       2017-04-05 20:43:45 +08:00
    @botman 谢谢。
    关于   ·   帮助文档   ·   博客   ·   API   ·   FAQ   ·   我们的愿景   ·   实用小工具   ·   2927 人在线   最高记录 6543   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 28ms · UTC 02:58 · PVG 10:58 · LAX 19:58 · JFK 22:58
    Developed with CodeLauncher
    ♥ Do have faith in what you're doing.