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 多線程

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM