Почему asynchttpclient в торнадо не отправляет запрос сразу?

В один прекрасный момент мне нужно много времени, чтобы подать неблокирующий запрос и за 2 секунды, с торнадо написать пример, помогите!

У меня есть программа Server Client на python, которая использует Tornado.

Сервер.py:

import tornado.httpserver
import tornado.ioloop
import random
import time

def handle_request(request):
    t = random.randint(1, 10) / 10.
    _str = "%s rep_time: %s delay %s" % (request.body, time.time(), t)
    time.sleep(t)
    request.write('HTTP/1.1 200 OK\r\nContent-Length: %s\r\n\r\n%s' % (len(_str), _str))
    request.finish()

http_server = tornado.httpserver.HTTPServer(handle_request)
http_server.listen(8888)
print "server start..."
tornado.ioloop.IOLoop.instance().start()

клиент.py:

# -*- coding: utf-8 -*-
from tornado.httpclient import AsyncHTTPClient, HTTPRequest
import tornado.ioloop
import time
from tornado.log import gen_log
from tornado import gen
from tornado.options import parse_command_line
import datetime

@gen.coroutine
def handle_requst(response):
    if response.body:
        gen_log.info("response body: %s" % response.body)

@gen.coroutine
def send_request(num):
    yield AsyncHTTPClient().fetch("http://localhost:8888", handle_requst, method="POST", body="req_time: %s no.: %s" % (time.time(), num))

@gen.coroutine
def run():
    begin_time = int(time.time() + 1)
    while True:
        yield gen.Task(tornado.ioloop.IOLoop.current().add_timeout, datetime.timedelta(seconds=1))
        now_time = int(time.time())

        if now_time == begin_time: 
            gen_log.info('begin_time:%s' % time.time())
            num = 0
            while True:
                num = num + 1
                if num < 10:
                    #Begin submitting data
                    send_request(num)
                # Submit two seconds
                if time.time() > (begin_time + 2):
                    break
            break
    gen_log.info('end_time:%s' % time.time())

if __name__ == '__main__':
    parse_command_line()
    tornado.ioloop.IOLoop.instance().add_callback(run)
    tornado.ioloop.IOLoop.instance().start()

результат

[I 141230 19:05:32 2:24] begin_time:1419937532.08
[I 141230 19:05:34 2:36] end_time:1419937534.0
[I 141230 19:05:34 2:11] response body: req_time: 1419937532.1 no.: 1 rep_time: 1419937534.0 delay 0.1

Время начала: 32 с
Время окончания: 34 с
Время запроса: 32 с
Время принятия сервером: 34 с

Как вы можете видеть, время приема сервера составляет 34 секунды, я хочу, чтобы время приема сервера было около 32 секунд.


person xu.    schedule 30.12.2014    source источник


Ответы (2)


Во-первых, у меня не установлен торнадо, чтобы проверить, но если изменить

yield AsyncHTTPClient().fetch("http://localhost:8888", handle_requst, method="POST", body="req_time: %s no.: %s" % (time.time(), num))

to:

AsyncHTTPClient().fetch("http://localhost:8888", handle_requst, method="POST", body="req_time: %s no.: %s" % (time.time(), num))

Я думаю, вы получите больше в соответствии с тем, что вы ожидаете (первый запрос передается мгновенно, вместо того, чтобы ждать, пока метод run() сломается, что занимает около 2 секунд).

Во-вторых, вы выполняете точное сравнение по времени (fx, если now_time == begin_time:), в этом примере вы округляете до int, поэтому оно будет работать как минимум несколько раз. Но использование таких методов в конечном итоге приведет к тому, что ваши программы взорвутся. Время в компьютерных часах не такое точное, как вы думаете, запущено много процессов, и спящий режим (0,1) может составлять более 0,1 секунды.

В-третьих, вы, похоже, ожидаете, что ваша система будет осуществлять мгновенную связь с сетевой картой, но этого не произойдет.

В-четвертых, то, что вы регистрируете как begin_time, не является переменной begin_time, и вы сохраняете rep_time, прежде чем дождаться задержки, которую вы вводите на сервере, не уверен, что это предназначено.

person Chewie    schedule 30.12.2014

time.sleep блокирует IOLoop, который не позволяет запускать что-либо еще (включая AsyncHTTPClient). Для бесперебойной работы торнадо необходимо заменить все блокирующие функции на неблокирующие эквиваленты (например, yield gen.Task(IOLoop.current().add_timeout, datetime.timedelta(seconds=1)) вместо time.sleep(1)).

person Ben Darnell    schedule 10.01.2015
comment
Привет, Бен, я изменил код, но все еще не получил желаемого эффекта. Я не знаю, как это сделать. - person xu.; 27.01.2015