多个同时发出的HTTP请求

时间:2016-08-16 15:34:58

标签: python multithreading api rest python-multithreading

我尝试根据API的某些处理来获取项目列表并检查其状态更改。该列表将手动填充,数量可能有几千个。

我正在尝试编写一个脚本,该脚本可以同时连接到API,以便继续检查状态更改。对于每个项目,一旦状态更改,检查的尝试必须停止。基于阅读Stackoverflow上的其他帖子(具体来说,What is the fastest way to send 100,000 HTTP requests in Python?),我提出了以下代码。但是在处理完列表一次后脚本总是会停止。我做错了什么?

我面临的另一个问题是键盘中断方法永远不会触发(我尝试使用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的新手,因此也可能存在语法错误......我绝对不熟悉多线程,所以也许我也做错了其他事情。

1 个答案:

答案 0 :(得分:0)

在代码中,列表只读一次。应该像

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进程终止。

如果我可以一般地发表一些评论。

  • 对于如此大的并发而言,线程并不是一个好的实现
  • 每次创建新连接效率不高

我建议的是

  1. 使用gevent for asynchronous network I/O
  2. 预先分配与并发号大小相同的连接队列,并在需要进行呼叫时让checkStatus获取连接对象。通过这种方式,连接可以保持活跃状态​​,重新使用,并且创建和销毁它们没有任何开销,并且增加了内存使用量。