• python利用多线程让http请求异步返回


    有时我们可能会碰到这样一种情况,我们有一个功能,这个功能对外提供了一个http接口,我们需要对这个http接口发起请求才能启动这个服务,但是这个服务功能可能会执行很久,这样如果等功能执行结束再返回请求结果,那这个请求可能就超时了,
     
    发起请求的客户端
    1 import requests
    2  
    3 req = requests.get("http://127.0.0.1:9898/register?username=aaa&pwd=232323")
    4 print(req.content)
     
    服务端
     1 # coding=utf-8
     2 import flask
     3 from flask import jsonify
     4 from flask import request
     5 
     6 from gevent import pywsgi
     7 
     8 import sys
     9 reload(sys)
    10 import time
    11 sys.setdefaultencoding('utf-8')
    12 
    13 server = flask.Flask(__name__)
    14 
    15 @server.route('/register', methods=['get', 'post'])
    16 def registerPost():
    17     # post请求获取请求的参数,返回结果类型是str
    18     username = request.values.get('username')
    19     pwd = request.values.get('pwd')
    20     app_id = request.values.get('app_id')
    21     dowork(app_id)
    22     # confirmpwd = request.values.get('confirmpwd')
    23     if username and pwd:  # 判断输入的用户名、密码、确认密码都不为空
    24         return ("用户名为:%s, 密码为:%s" % (username, pwd))
    25     else:
    26         return jsonify({"code": 504, "msg": "必填项不能为空"})
    27 
    28 
    29 if __name__ == '__main__':
    30     # port可以指定端口,默认端口是5000
    31     # host默认是127.0.0.1,写成0.0.0.0的话,其他人可以访问,代表监听多块网卡上面,
    32     # server.run(debug=True, port=9898, host='0.0.0.0')
    33     server = pywsgi.WSGIServer(('0.0.0.0', 9898), server)
    34     server.serve_forever()
    这个就是一个典型的同步返回结果,发起请求后,必须等 dowork() 功能执行完之后才能返回请求结果,如果 dowork() 执行时间较长,则会导致客户端请求超时
     
    这时我们可能就需要一个异步的http接口,收到客户端的请求后,马上返回一个请求结果,然后再慢慢的执行要执行的任务,这个过程怎么实现呢,我的做法是通过多线程来实现,在服务端的响应函数中,每次收到一个请求,获取请求中携带的参数,然后用这些参数创建一个会执行我们功能服务的线程,最后返回请求结果,这样客户端可以很快获取到请求结果,从而不会让客户端请求超时
     
    下面是加入了线程的服务端的响应函数
     1 # coding=utf-8
     2 import flask
     3 from flask import jsonify
     4 from flask import request
     5 
     6 from gevent import pywsgi
     7 
     8 import sys
     9 reload(sys)
    10 import time
    11 sys.setdefaultencoding('utf-8')
    12 
    13 server = flask.Flask(__name__)
    14 
    15 import threading
    16 import time
    17 
    18 exitFlag = 0
    19 
    20 class myThread (threading.Thread):
    21     def __init__(self, threadID, name, counter, app_id):
    22         threading.Thread.__init__(self)
    23         self.threadID = threadID
    24         self.name = name
    25         self.counter = counter
    26         self.app_id = app_id
    27     def run(self):
    28         print ("开始线程:" + self.name)
    29         print_time(self.name, self.counter, 1, self.app_id)
    30         print ("退出线程:" + self.name)
    31 
    32 def print_time(threadName, delay, counter, app_id):
    33     while counter:
    34         if exitFlag:
    35             threadName.exit()
    36         time.sleep(delay)
    37         print ("%s: %s" % (threadName, time.ctime(time.time())))
    38         dowork(app_id)
    39         counter -= 1
    40 
    41 @server.route('/register', methods=['get', 'post'])
    42 def registerPost():
    43     # post请求获取请求的参数,返回结果类型是str
    44     username = request.values.get('username')
    45     pwd = request.values.get('pwd')
    46     app_id = request.values.get('app_id')
    47 
    48     # 创建新线程
    49     thread1 = myThread(1, "Thread-1", 1, app_id)
    50     # 开启新线程
    51     thread1.start()
    52 
    53     # confirmpwd = request.values.get('confirmpwd')
    54     if username and pwd:  # 判断输入的用户名、密码、确认密码都不为空
    55         return ("用户名为:%s, 密码为:%s" % (username, pwd))
    56     else:
    57         return jsonify({"code": 504, "msg": "必填项不能为空"})
    58 
    59 
    60 if __name__ == '__main__':
    61     # port可以指定端口,默认端口是5000
    62     # host默认是127.0.0.1,写成0.0.0.0的话,其他人可以访问,代表监听多块网卡上面,
    63     # server.run(debug=True, port=9898, host='0.0.0.0')
    64     server = pywsgi.WSGIServer(('0.0.0.0', 9898), server)
    65     server.serve_forever()
     
    因为线程的run()方法和start()方法是不能传递参数的,所以如果我们需要从请求中获取参数然后传递给要执行的功能的话,可以在线程的构造方法的参数中加上我们需要传递的参数,这样在run()方法内部我们就能动态获得请求中传递的参数了
     
    下面是菜鸟教程里面的多线程模板
     1 #!/usr/bin/python3
     2 
     3 import threading
     4 import time
     5 
     6 class myThread (threading.Thread):
     7     def __init__(self, threadID, name, counter):
     8         threading.Thread.__init__(self)
     9         self.threadID = threadID
    10         self.name = name
    11         self.counter = counter
    12     def run(self):
    13         print ("开启线程: " + self.name)
    14         # 获取锁,用于线程同步
    15         threadLock.acquire()
    16         print_time(self.name, self.counter, 3)
    17         # 释放锁,开启下一个线程
    18         threadLock.release()
    19 
    20 def print_time(threadName, delay, counter):
    21     while counter:
    22         time.sleep(delay)
    23         print ("%s: %s" % (threadName, time.ctime(time.time())))
    24         counter -= 1
    25 
    26 threadLock = threading.Lock()
    27 threads = []
    28 
    29 # 创建新线程
    30 thread1 = myThread(1, "Thread-1", 1)
    31 thread2 = myThread(2, "Thread-2", 2)
    32 
    33 # 开启新线程
    34 thread1.start()
    35 thread2.start()
    36 
    37 # 添加线程到线程列表
    38 threads.append(thread1)
    39 threads.append(thread2)
    40 
    41 # 等待所有线程完成
    42 for t in threads:
    43     t.join()
    44 print ("退出主线程")
    执行以上程序,输出结果为:
    开启线程: Thread-1
    开启线程: Thread-2
    Thread-1: Wed Apr  6 11:52:57 2016
    Thread-1: Wed Apr  6 11:52:58 2016
    Thread-1: Wed Apr  6 11:52:59 2016
    Thread-2: Wed Apr  6 11:53:01 2016
    Thread-2: Wed Apr  6 11:53:03 2016
    Thread-2: Wed Apr  6 11:53:05 2016

    参考:

    Python3 多线程

     
  • 相关阅读:
    Asp.Net MVC3.0中防止跨站的POST
    .NET实现字符串base64编码
    silverlight调用MVC WebApi方法
    MVC实现上传图片的方法
    ASP.NET使用文件上传控件上传图片
    设置网页icon标志
    C# 连接EXCEL 和 ACCESS
    javascript前进、后退、刷新的实现
    DataTable数据统计方法
    常量指针和指针常量
  • 原文地址:https://www.cnblogs.com/hi3254014978/p/13622113.html
Copyright © 2020-2023  润新知