多執行緒和多程序的資源消耗對比
1、測試環境配置如下:
虛擬機器:Ubuntu16.04 4G記憶體 雙核處理器
執行環境python+flask+gunicorn+nginx
flask 、nginx和 gunicorn 安裝方法都非常簡單粗暴:sudo apt-get install 就好
這裡我們為了使用一個域名來代替訪問預設的127.0.0.1:8080,將配置nginx如下:
在/etc/nginx/conf.d 下新建檔案flask_nginx.conf 新增如下內容: proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; server { listen 80; server_name www.flasktest.com; location / { proxy_pass http://127.0.0.1:8080; access_log /home/api_access.log; proxy_read_timeout 300; } } 在/etc/hosts檔案中新增一行 127.0.0.1 www.flasktest.com
通過如上配置,我們就可以通過訪問www.flasktest.com域名來訪問127.0.0.1:8080埠下的內容啦~
2、具體程式碼:
from flask import Flask,request,jsonify from flask_restful import reqparse, abort, Api, Resource import time app = Flask(__name__) api = Api(app) # 這是第一個介面 class task_1(Resource): def get(self): #這裡的get函式,指定處理get請求 parser = reqparse.RequestParser() parser.add_argument("url", type=str, location="args", required=False) parser.add_argument("type", type=int, location="args", required=False) parser.add_argument("id", type=str, location="args", required=False) params = parser.parse_args(strict=False) print(params) if params['action'] == 'fresh': #run something return 'vuln.cn demo 1' else: #run something return 'hello vuln.cn' # 這是第二個介面 class task_2(Resource): #global num #num = 1000 def get(self): #global num #num -= 1 s = time.time() count = 0 for i in range(0,1000000): //實現cpu計算 count += i #time.sleep(2) //實現I/O parser = reqparse.RequestParser() parser.add_argument("id", type=str, location="args", required=False) params = parser.parse_args(strict=False) #run something e = time.time() run_time = e - s res = {} res['time'] = run_time #res['num'] = num return res #路由地址分別對應處理的類 api.add_resource(task_1, '/demo1/') #實現介面:http://127.0.0.1:8080/demo1/?url=xxx&type=xxx&id=xxx api.add_resource(task_2, '/demo2/') #實現介面:http://127.0.0.1:8080/demo2/?id=xxx if __name__ == '__main__': app.run(debug=True)
這裡我們只使用了介面二:同時因為我們之前在nginx下的配置,我們也可以通過訪問http://www.flasktest.com/demo2/?id=xxx來進行實驗。
程式中for迴圈是為了獲得cpu計算所消耗的時間,而sleep則是為了獲得I/O所消耗的時間。
3、使用gunicorn在伺服器端啟動多進/執行緒
啟動多個程序:
gunicorn -w 40 -t 60000 flask_rest_test:app -b 0.0.0.0:8080
引數解釋:-w 指定啟動的程序數
-t 指定超時時間 預設30s
flask_rest_test:app 前半部分為檔名稱,後半部分為app的名字,對應程式碼中app = Flask(__name__)
-b 指定IP和埠號執行 0.0.0.0 表示接受所有IP訪問
啟動多個執行緒:
gunicorn -w 1 --threads 40 -t 60000 flask_rest_test:app -b 0.0.0.0:8080
引數解釋:與上面相比多出了一個threads引數
--threads 指定啟動的執行緒數
4、使用CURL發起多併發請求
指令碼如下:新建formuti.sh,內容如下:
stime=$(date +%s);
#echo "${stime}";
for((i=0;i<700;i++));
do
{
curl -v http://www.flasktest.com/demo2/?id=2222;
}&
done
wait
etime=$(date +%s);
((run_time = etime - stime));
#((run_time = run_time * 1000))
echo "${run_time}"s;
#echo $num;
這段程式碼表示同時發起700個併發請求,程式中&表示 去併發提交函式中的內容,而不是執行完一個,再去迴圈執行下一個。
wait表示前面的程式全部執行完,才會繼續執行下面的命令。
5、實驗結果
0-1000000加法:
sleep2秒的時間消耗:
6、總結
對於cpu計算來說,越高併發並且開啟的進/執行緒越多,同等情況相比較而言,執行緒執行時間越短。其他情況則程序執行時間較短。對於cpu計算來說,併發數和開啟進/執行緒都較低的情況,選用多程序為更好的選擇,若併發數目過高和開啟的進/執行緒較多的情況,易選用多執行緒。
對於I/O來說,併發數目和開啟的進/執行緒較少的情況下,執行時間相差無幾。當併發數遠遠大於開啟的進/執行緒時,程序執行時間較短,但是存在訪問被丟棄。其他情況則執行緒執行時間較短。另外開啟程序數目過多,非常容易卡死。所以對於I/O來說,多執行緒為一個更好的選擇。