python - tornado框架调用AsyncHTTPClient,出现阻塞并严重延迟的问题?
巴扎黑
巴扎黑 2017-04-18 09:57:20
[Python讨论组]

1,我有用tornado框架搭建了一个web服务对外提供访问,我们暂且叫他A服务,这个A服务实际上就是调用本机的另一个web服务(也是tornado搭建的)我们暂且叫它B服务,如果B服务返回不是200,就调用另一个web服务(也是tornado搭建的)我们暂且叫它C服务,都是本机localhost调用,我发现被调用的B,C服务都很快结束,不到1秒,而A服务这边做的时间计时,发现很慢,达到20秒,请各位帮我看看!

我用的python2.7,tornado3.2

2,以下是代码

@asynchronous
@gen.coroutine
def get(self):
    cost_array=[int(time.time()*1000)]
    result=yield self.callB(q,start_date)
    cost_array.append(int(time.time()*1000))
    if result["code"]!=200:
        result=yield self.callC(q,start_date)
        cost_array.append(int(time.time() * 1000))
        
    self.set_status(result["code"])
    self.write(result["response"])
    
   @gen.coroutine
def callB(self, q, start_date):
    result={
        "code":0,
        "response":{}
    }
    url="http://localhost:8200/*?q=%s&startdate=%s"%(q,start_date)
    request = HTTPRequest(url=url,\
                          method="GET", \
                          follow_redirects=False,\
                          request_timeout=3000)
    sever_response=yield gen.Task(AsyncHTTPClient().fetch,request)

    result["code"]=sever_response.code
    if sever_response.body:
        result["response"]=sever_response.body
    raise gen.Return(result)
    
@gen.coroutine
def callC(self, q, start_date):
    result={
        "code":0,
        "response":{}
    }
    url="http://localhost:8200/*?q=%s&startdate=%s"%(q,start_date)
    request = HTTPRequest(url=url,\
                          method="GET", \
                          follow_redirects=False,\
                          request_timeout=3000)
    sever_response=yield gen.Task(AsyncHTTPClient().fetch,request)

    result["code"]=sever_response.code
    if sever_response.body:
        result["response"]=sever_response.body
    raise gen.Return(result)
    

以上代码执行一段时间还行,过了一段时间后,cost_array数组里面记录的时间戳直接差距的秒数能达到20秒以上,然后服务也没办法对外提供访问了,但进程的cpu和内存占用很小!!访问都是超时了。只能重启服务

巴扎黑
巴扎黑

全部回复(2)
PHP中文网

首先,吐槽几句:

  1. 没有说明使用的python、tornado版本,服务器版本(虽然服务器版本估计不涉及)

  2. 代码没有格式化

  3. 既然给出的是A服务的代码,示例里面竟然还有CallA CallC,那么,这段代码是"B"?

  4. 没有给出完整可以执行的脚本,包括B、C服务,你贴了一个30%完成度的代码段,然后期待别人给你补全剩下70%的测试代码(连main函数部分都没有),完成B、C服务的部分,并且给出完整的解释并告知你如何错了?这个不是不懂,是懒。

百度“提问的智慧”会很有帮助。

顺手帮你补全了A,B,C的代码,而这段代码是全路通秒回。

A

# -*- coding: utf-8 -*-

import os
import logging
import tornado
import tornado.ioloop
import tornado.options
from tornado.options import define, options
from tornado.web import RequestHandler as BaseRequestHandler
from tornado.httpclient import HTTPRequest, AsyncHTTPClient
from tornado import gen
from tornado.web import asynchronous
import time


class XHandler(BaseRequestHandler):
    @asynchronous
    @gen.coroutine
    def get(self):
        q = self.get_argument("q", "")  # 缺失
        start_date = self.get_argument("start_date", "20161010")  # 缺失
        cost_array = [int(time.time() * 1000)]
        result = yield self.callB(q, start_date)
        cost_array.append(int(time.time() * 1000))
        if result["code"] != 200:
            logging.info("calling C")
            result = yield self.callC(q, start_date)
            cost_array.append(int(time.time() * 1000))
        else:
            logging.info("no need call C")
        self.set_status(result["code"])

        logging.info("call cost time %s", cost_array)
        self.write(result["response"])

    @gen.coroutine
    def callB(self, q, start_date):
        result = {"code": 0, "response": {}}
        url = "http://127.0.0.1:8100/?q=%s&startdate=%s" % (q, start_date)
        request = HTTPRequest(url=url,\
                              method="GET", \
                              follow_redirects=False,\
                              request_timeout=3000)
        sever_response = yield gen.Task(AsyncHTTPClient().fetch, request)

        result["code"] = sever_response.code
        if sever_response.body:
            result["response"] = sever_response.body
        raise gen.Return(result)

    @gen.coroutine
    def callC(self, q, start_date):
        result = {"code": 0, "response": {}}
        url = "http://127.0.0.1:8200/?q=%s&startdate=%s" % (q, start_date)
        request = HTTPRequest(url=url,\
                              method="GET", \
                              follow_redirects=False,\
                              request_timeout=3000)
        sever_response = yield gen.Task(AsyncHTTPClient().fetch, request)

        result["code"] = sever_response.code
        if sever_response.body:
            result["response"] = sever_response.body
        raise gen.Return(result)


class Application(tornado.web.Application):
    def __init__(self):
        handlers_ = [(r'/', XHandler), ]
        tornado.web.Application.__init__(self, handlers_)


def main():
    tornado.options.parse_command_line()
    app = Application()
    logging.info("service started.")
    app.listen(8000)
    tornado.ioloop.IOLoop.instance().start()


if __name__ == "__main__":
    main()

B

# -*- coding: utf-8 -*-

import os
import logging
import tornado
import tornado.ioloop
import tornado.options
from tornado.options import define, options
from tornado.web import RequestHandler as BaseRequestHandler

from tornado.httpclient import HTTPRequest, AsyncHTTPClient
from tornado import gen
from tornado.web import asynchronous
import time
import json


class BHandler(BaseRequestHandler):
    @asynchronous
    @gen.coroutine
    def get(self):
        self.set_status(202)
        self.write(json.dumps({"msg": "later"}))


class Application(tornado.web.Application):
    def __init__(self):
        handlers_ = [(r'/', BHandler), ]
        tornado.web.Application.__init__(self, handlers_)


def main():
    tornado.options.parse_command_line()
    app = Application()
    logging.info("service started.")
    app.listen(8100)
    tornado.ioloop.IOLoop.instance().start()


if __name__ == "__main__":
    main()

C

# -*- coding: utf-8 -*-

import os
import logging
import tornado
import tornado.ioloop
import tornado.options
from tornado.options import define, options
from tornado.web import RequestHandler as BaseRequestHandler

from tornado.httpclient import HTTPRequest, AsyncHTTPClient
from tornado import gen
from tornado.web import asynchronous
import time
import json


class CHandler(BaseRequestHandler):
    @asynchronous
    @gen.coroutine
    def get(self):
        self.write(json.dumps({"msg": "later"}))


class Application(tornado.web.Application):
    def __init__(self):
        handlers_ = [(r'/', CHandler), ]
        tornado.web.Application.__init__(self, handlers_)


def main():
    tornado.options.parse_command_line()
    app = Application()
    logging.info("service started.")
    app.listen(8200)
    tornado.ioloop.IOLoop.instance().start()


if __name__ == "__main__":
    main()

给几个定位的思路:

  1. A服务的调用超时应该是没有设置成功,从20s数值来看,根本就是超时了。

  2. 使用curl模拟调用B,C,确认这俩真的是秒回。

  3. A多打点日志,看到底卡在哪里。

天蓬老师

将代码:

url="http://localhost:8200/*?q=%s&startdate=%s"%(q,start_date)
request = HTTPRequest(url=url,\
                          method="GET", \
                          follow_redirects=False,\
                          request_timeout=3000)
sever_response=yield gen.Task(AsyncHTTPClient().fetch,request)

改为以下方式即可:

sever_response=yield AsyncHTTPClient().fetch(url)

即可

热门教程
更多>
最新下载
更多>
网站特效
网站源码
网站素材
前端模板
关于我们 免责申明 意见反馈 讲师合作 广告合作 最新更新 English
php中文网:公益在线php培训,帮助PHP学习者快速成长!
关注服务号 技术交流群
PHP中文网订阅号
每天精选资源文章推送
PHP中文网APP
随时随地碎片化学习
PHP中文网抖音号
发现有趣的

Copyright 2014-2025 https://www.php.cn/ All Rights Reserved | php.cn | 湘ICP备2023035733号