有时我们可能会碰到这样一种情况,我们有一个功能,这个功能对外提供了一个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 多线程