使用 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.cn 与 http://hzjfwj.com 是无法访问的。
urllib.urlrequest.urlopen 与 requests 一样会等待,有什么办法可以不在那个无法访问的网址上等待?
还是我的多线程姿势用错了?望指教。
python 3.4.1 64位 requests2.9.1 windows 7 64位。
1
bazingaterry 2017-04-03 12:23:24 +08:00 via iPhone
pool.join() 的意思不就是等待所有线程结束吗?
|
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)超时就好了 |
3
cyrbuzz OP @bazingaterry
pool.join()是等待所有线程结束不过运行到不能打开的网址时会一直等待那一个线程。 |
4
cyrbuzz OP |
6
cyrbuzz OP @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 |
7
xiaoyu233 2017-04-03 12:46:01 +08:00
@cyrbuzz http://jy-qj.com.cn 这个不管你设置多少都是秒报错啊,他域名都没解析,更新下 requests 版本吧,我测试没出现你这情况
|
9
xiaoyu233 2017-04-03 12:58:36 +08:00 1
@cyrbuzz 或者 requests 前先 ping 如果 Unknown host 直接 break =,=||
|
10
cyrbuzz OP @xiaoyu233 更新成 2.13.0 ,还是要等老长时间。在虚拟机 32 位 win7 32 位 python 测试等待的时间少些,没达到秒报错。
先用 ping 检测下了。 |
13
xiaoyu233 2017-04-03 13:28:14 +08:00
@cyrbuzz 不知道,好像没卡在一个线程上啊,只是程序好像要等待所有线程结束,你可以用 BoundedSemaphore 来控制阻塞
|
14
a87150 2017-04-03 13:31:32 +08:00
我试怎么没问题?
|
15
cyrbuzz OP |
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 |
17
botman 2017-04-04 11:34:07 +08:00 via Android
requests timeout + 线程 timeout, 用 requests 有时确实会发生永久阻塞不解析的问题 原因比较难找 多半可能和系统环境有关系 保险的方式还是给每个线程都加 timeout
|
18
cyrbuzz OP @botman 抛开自己写,有没有可以自带线程超时的包,
from concurrent.futures import ThreadPoolExecutor 一般用这个线程池,他的 map 方法有一个 timeout ,不过尝试后发现没效果。 |