我试图采取项目列表,并检查他们的状态变化基于某些处理的API。该列表将手动填充,数量可以变化到几千个。
我试图写一个脚本,使多个同时连接到API,以保持检查状态的变化。对于每个项目,一旦状态改变,检查的尝试必须停止。基于阅读Stackoverflow上的其他帖子(具体来说,在Python中发送100,000个HTTP请求的最快方法是什么?),我编写了以下代码。但是脚本总是在处理列表一次之后停止。我做错了什么?
我面临的另一个问题是键盘中断方法永远不会触发(我正在尝试使用Ctrl+C,但它不会杀死脚本。
from urlparse import urlparse
from threading import Thread
import httplib, sys
from Queue import Queue
requestURLBase = "https://example.com/api"
apiKey = "123456"
concurrent = 200
keepTrying = 1
def doWork():
while keepTrying == 1:
url = q.get()
status, body, url = checkStatus(url)
checkResult(status, body, url)
q.task_done()
def checkStatus(ourl):
try:
url = urlparse(ourl)
conn = httplib.HTTPConnection(requestURLBase)
conn.request("GET", url.path)
res = conn.getresponse()
respBody = res.read()
conn.close()
return res.status, respBody, ourl #Status can be 210 for error or 300 for successful API response
except:
print "ErrorBlock"
print res.read()
conn.close()
return "error", "error", ourl
def checkResult(status, body, url):
if "unavailable" not in body:
print status, body, url
keepTrying = 1
else:
keepTrying = 0
q = Queue(concurrent * 2)
for i in range(concurrent):
t = Thread(target=doWork)
t.daemon = True
t.start()
try:
for value in open('valuelist.txt'):
fullUrl = requestURLBase + "?key=" + apiKey + "&value=" + value.strip() + "&years="
print fullUrl
q.put(fullUrl)
q.join()
except KeyboardInterrupt:
sys.exit(1)
我是Python的新手,所以也可能有语法错误…我肯定不熟悉多线程,所以也许我做错了其他的东西,以及
在代码中,该列表只被读取一次。应该是像
try:
while True:
for value in open('valuelist.txt'):
fullUrl = requestURLBase + "?key=" + apiKey + "&value=" + value.strip() + "&years="
print fullUrl
q.put(fullUrl)
q.join()
对于中断的事情,删除checkStatus中的裸except
行或使其为except Exception
。裸异常将捕获所有异常,包括SystemExit
,这是sys.exit
引发的,并阻止python进程终止。
如果我可以做一些一般性的评论。
- 对于如此大的并发来说,线程不是一个很好的实现
- 每次都创建新连接效率不高
我的建议是
- 异步网络I/O使用gevent
- 预先分配一个与并发数相同大小的连接队列,并在需要调用时让
checkStatus
抓取连接对象。这样,连接保持活跃,被重用,并且没有创建和销毁它们的开销,也没有随之增加的内存使用。