2016-06-21 103 views
0

我希望以固定的时间间隔向服务器发送GET请求并记录请求和响应时间。这个间隔可以是几十毫秒的量级。 我的第一种方法是使用线程池,如本答案https://stackoverflow.com/a/2635066/2390362中所述。然后,只要时间间隔过去,我就会将一个任务放入队列中,现在是发出请求的时间。虽然这有效,但它似乎不太好。使用Tornado测量响应的时间AsyncHTTPClient

我在另一个回答中遇到了Tornado https://stackoverflow.com/a/25549675/2390362。这对于较重的负载似乎表现得更好。这大致是我如何适应它来做我上面描述的。

import time 
from tornado import ioloop, httpclient 
from datetime import datetime, timedelta 
from functools import partial 

i = 0 

def handle_request(req_time, log, response): 
    resp_time = datetime.now() 
    log.write("%s,\t%s,\t%s,\t%s\n"%(req_time.time(), resp_time.time(), (resp_time - req_time).total_seconds(), response.code)) 
    global i 
    i -= 1 
    if i == 0: 
     ioloop.IOLoop.instance().stop() 


def do_intervals(): 
    http_client = httpclient.AsyncHTTPClient() 
    req_count_limit = 3000 
    interval = 0.01 
    url = "http://www.someurl.com/" 
    global i 

    with open("log_file.log", 'a') as log: 

     for job_counter in range(req_count_limit): 

      i += 1 

      req_time = datetime.now() 
      current_callback = partial(handle_request, req_time, log) 
      http_client.fetch(url.strip(), current_callback, method='GET') 
      time.sleep(interval) 
     ioloop.IOLoop.instance().start() 


if __name__ == '__main__': 
    do_intervals() 

不过,我注意到,当响应到达的回调函数调用只有所有的请求已发送后执行的,而不是。这使我对响应时间的测量不准确。我刚刚发现了Tornado,并不完全确定那里的代码是如何工作的。有没有办法获得我错过的响应时间,或者这是龙卷风和异步HTTP工作的唯一方式?

回答

0

handle_request,请求的持续时间可以用resp_time - req_time合理测量。

问题是,您正在用time.sleep阻止事件循环,这意味着大多数处理在初始for循环完成之前不会取得进展。见Why isn’t this example with time.sleep() running in parallel? 试着这么做:

@gen.coroutine 
def do_intervals(): 
    # ... existing code ... 
    yield gen.sleep(interval) # instead of time.sleep 

do_intervals删除IOLoop.instance().start()。 运行它喜欢:

IOLoop.instance().run_sync(do_intervals) 
+0

由于'收率gen.sleep(间隔)'跳出循环的,我把部分内循环在一个单独的'@ gen.coroutine'功能和用于'gen.sleep ()'。但是,在所有请求被发送后,它似乎仍然在调用处理程序。 –

+0

不,如果你想在循环时以非阻塞的方式睡眠,你真的需要在循环迭代过程中产生gen.sleep(interval)。如果你使用'gen.coroutine'来装饰你的'do_intervals',并按照我的指示进行操作,它就会按你的要求工作。我已经更新了我的答案,以便更清楚。 –

+0

我尝试使用'ioloop.PeriodicCallback'工作,但你的解决方案似乎更好地扩展(我会跳过一些回调)。 PS:我还必须删除'ioloop.IOLoop.instance()。stop()',否则我会得到一个'TimeOutError' –

相关问题