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

2017-04-03 12:07:24 +08:00
 cyrbuzz

使用 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 一样会等待,有什么办法可以不在那个无法访问的网址上等待?

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

7284 次点击
所在节点    Python
20 条回复
bazingaterry
2017-04-03 12:23:24 +08:00
pool.join() 的意思不就是等待所有线程结束吗?
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
2017-04-03 12:29:47 +08:00
@bazingaterry
pool.join()是等待所有线程结束不过运行到不能打开的网址时会一直等待那一个线程。
cyrbuzz
2017-04-03 12:30:20 +08:00
@xiaoyu233
http://jy-qj.com.cn 这个网址设置 timeout 无效。。
xiaoyu233
2017-04-03 12:34:42 +08:00
@cyrbuzz 无效是什么意思,我运行了没发现问题啊
cyrbuzz
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
2017-04-03 12:46:01 +08:00
@cyrbuzz http://jy-qj.com.cn 这个不管你设置多少都是秒报错啊,他域名都没解析,更新下 requests 版本吧,我测试没出现你这情况
wisefree
2017-04-03 12:49:58 +08:00
@xiaoyu233 这个是正解,在 requests 设置 timeout
xiaoyu233
2017-04-03 12:58:36 +08:00
@cyrbuzz 或者 requests 前先 ping 如果 Unknown host 直接 break =,=||
cyrbuzz
2017-04-03 13:12:20 +08:00
@xiaoyu233 更新成 2.13.0 ,还是要等老长时间。在虚拟机 32 位 win7 32 位 python 测试等待的时间少些,没达到秒报错。
先用 ping 检测下了。
xiaoyu233
2017-04-03 13:13:26 +08:00
@cyrbuzz 我不是 win 系统😊
cyrbuzz
2017-04-03 13:16:17 +08:00
@xiaoyu233 不过还有个问题,既然是多线程,那就让哪一个线程等待就是了,为什么会卡在一个线程上呢。。
xiaoyu233
2017-04-03 13:28:14 +08:00
@cyrbuzz 不知道,好像没卡在一个线程上啊,只是程序好像要等待所有线程结束,你可以用 BoundedSemaphore 来控制阻塞
a87150
2017-04-03 13:31:32 +08:00
我试怎么没问题?
cyrbuzz
2017-04-03 13:50:28 +08:00
@xiaoyu233
@a87150
你们的 python 都是什么版本。我更新下 python 看看是不是 python 的问题。
我这边只要不是无法解析的网址都是正常运行,一有无法解析的就卡主一会。。
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
2017-04-04 11:34:07 +08:00
requests timeout + 线程 timeout, 用 requests 有时确实会发生永久阻塞不解析的问题 原因比较难找 多半可能和系统环境有关系 保险的方式还是给每个线程都加 timeout
cyrbuzz
2017-04-04 17:25:31 +08:00
@botman 抛开自己写,有没有可以自带线程超时的包,
from concurrent.futures import ThreadPoolExecutor
一般用这个线程池,他的 map 方法有一个 timeout ,不过尝试后发现没效果。
botman
2017-04-04 21:56:10 +08:00
@cyrbuzz python 标准库 threading 的 join 自带 timeout 用起来很简单的,还有就是看看 gevent 这个是用协程实现的并发框架非常的好用, timeout 也有好几种实现,具体细节请自行搜索相关 sample 和文档。
cyrbuzz
2017-04-05 20:43:45 +08:00
@botman 谢谢。

这是一个专为移动设备优化的页面(即为了让你能够在 Google 搜索结果里秒开这个页面),如果你希望参与 V2EX 社区的讨论,你可以继续到 V2EX 上打开本讨论主题的完整版本。

https://www.v2ex.com/t/352275

V2EX 是创意工作者们的社区,是一个分享自己正在做的有趣事物、交流想法,可以遇见新朋友甚至新机会的地方。

V2EX is a community of developers, designers and creative people.

© 2021 V2EX