1. 程式人生 > >Flask速成專案:Flask實現計算機資源的實時監控

Flask速成專案:Flask實現計算機資源的實時監控

很多人都說使用Python開發WEB應用非常方便,那麼對於WEB新手來說,到底有多方便呢?本文即將展示給你Python的魔法。 本文將通過一個例項:Flask實現計算機資源的實時監控,迅速帶你入門Flask開發。 先說一下我的水平,博主的專業並不是做WEB開發的,對於WEB方面,只會寫爬蟲,因此,只能看懂html,略看得懂css與js,我估計有很多像我一樣的小夥伴,因此,如果你的WEB掌握的水平在我之上或與我相當,那麼,這篇文章將是你迅速入門Flask的終極教程

先放上一張成果圖: 結果 訪問,瀏覽器能夠實時顯示我的電腦的兩個CPU的使用情況,這裡特地採用兩種顯示方式,方便大家學習程式碼。

flask介紹

Flask is a microframework for Python based on Werkzeug, Jinja 2 and good intentions. And before you ask: It’s BSD licensed! 搞科研或者搞技術,還是直接看英文吧,英文是你走向NB的基礎。

flask安裝

可以參考我之前的文章:

另外,需要安裝psutilflask_socketio包,可直接使用pip安裝

構建flask專案結構

在你的目錄下新建如下的目錄與檔案:

[email protected]:~/Desktop/projects/CPU_memory$ tree
.
|-- app.py `-- templates `-- index.html 1 directory, 2 files

非常形象的解釋下flask完成的任務 *** 瀏覽器向伺服器傳送請求,伺服器將html原始碼傳送給瀏覽器,瀏覽器將html解析成視覺化的東西展示給使用者。也就是說,使用者接收到的總是一個html檔案,那flask在整個過程中完成了什麼任務呢? 請把Flask想象成一個火腿腸加工廠*,將輸送給火腿腸加工廠火腿腸加工廠生產出火腿腸。同樣,將使用者請求,例如訪問https://xujh.top這一請求傳送給flaskflask能夠生產出html。 將請求傳送給flask

是通過flask中的路由來實現的,flask是通過直接返回或返回模板來生成html的。

對於上述專案結構的構成,app.py中實現了路由及啟動功能,templates資料夾中是模板檔案,(這裡插一句:我曾經看到很多人,在讀某個用flask做的WEB專案的原始碼,一開啟templates資料夾中,發現了很多css,js,html檔案,一開啟這些檔案,發現幾百上前行,一下子頭都大了,立馬放棄了讀程式碼,哈哈哈哈),其實,對於像我一樣專業不是做前端的小夥伴,完全可以不用擔心,這些檔案其實可以一行都不寫,例如可以用Bootstrap框架來做前端,使用Bootstrap要寫程式碼?兄弟,你不會用視覺化編輯工具嘛!!! 等以後我們做大專案,我們主要寫的也就是除了templates資料夾中以外的檔案。前端不會別擔心,我也不會。

對於這篇文章所要實現的目標,我們做一個小結:

  1. 執行app.py,計算機啟動flask自帶的伺服器,開始允許WEB訪問
  2. 使用者使用瀏覽器訪問網址
  3. flask接受到使用者的請求後,app.py進行邏輯上的處理,將index.html傳送給瀏覽器。

原始碼分析

原始碼的分析在註釋中,大家一定能看懂!

# -*- coding:utf-8 -*-
'''
CPU_and_MEM_Monitor
思路:後端後臺執行緒一旦產生資料,即刻推送至前端。
好處:不需要前端ajax定時查詢,節省伺服器資源。
'''

import psutil    #這個庫可以用來獲取系統的資源資料,詳細可以看文件
import time

from threading import Lock

from flask import Flask, render_template, session, request
from flask_socketio import SocketIO, emit

# Set this variable to "threading", "eventlet" or "gevent" to test the
# different async modes, or leave it set to None for the application to choose
# the best option based on installed packages.
async_mode = None

app = Flask(__name__)
app.config['SECRET_KEY'] = 'secret!'
socketio = SocketIO(app, async_mode=async_mode)


thread = None
thread_lock = Lock()



# 後臺執行緒 產生資料,即刻推送至前端
def background_thread():
    count = 0
    while True:
        socketio.sleep(2)
        count += 1
        t = time.strftime('%M:%S', time.localtime()) # 獲取系統時間(只取分:秒)
        cpus = psutil.cpu_percent(interval=None, percpu=True) # 獲取系統cpu使用率 non-blocking
        socketio.emit('server_response',
                      {'data': [t] + list(cpus)[0:4], 'count': count},
                      namespace='/test') # 注意:這裡不需要客戶端連線的上下文,預設 broadcast = True !!!!!!!
        print [t] +list(cpus)[0:4]
        print 100*'*'

# 當用戶訪問'/'時,執行index()函式。這也是python裝飾器的用法。
@app.route('/')
def index():
    return render_template('index.html', async_mode=socketio.async_mode)
    # 每次執行render_template函式時,渲染器都會將index.html的變數值用其實際值替代。


# 與前端建立 socket 連線後,啟動後臺執行緒
@socketio.on('connect', namespace='/test')
def test_connect():
    global thread
    with thread_lock:
        if thread is None:
            thread = socketio.start_background_task(target=background_thread)




if __name__ == '__main__':
    socketio.run(app, debug=True)

index.html

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="utf-8">
    <title>CPU_and_MEM_Monitor</title>
    <script type="text/javascript" src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
    <script type="text/javascript" src="https://cdn.bootcss.com/socket.io/1.5.1/socket.io.min.js"></script>
    <!-- ECharts 3 引入 -->
    <script src="http://echarts.baidu.com/dist/echarts.min.js"></script>
</head>

<body>
    <!--為ECharts準備一個具備大小(寬高)的Dom-->
    <div id="CPU1" style="height:500px;border:1px solid #ccc;padding:10px;"></div>
    <div id="CPU2" style="height:500px;border:1px solid #ccc;padding:10px;"></div>
    <script type="text/javascript">

    //--- 折柱 ---
    // 3個全域性變數:time、cpu1、cpu2
    var time = ["","","","","","","","","",""],
        cpu1 = [0,0,0,0,0,0,0,0,0,0],
        cpu2 = [0,0,0,0,0,0,0,0,0,0]

    //第一張echarts圖初始化
    var CPU1 = echarts.init(document.getElementById('CPU1'));
    CPU1.setOption({
        title: {
            text: 'CPU1'
        },
        tooltip: {},
        legend: {
            data:['cpu1']
        },
        xAxis: {
            data: []
        },
        yAxis: {},
        series: [{
            name: 'cpu1',
            type: 'line',
            data: []
        }]
    });
        

    //準備好的 callback 函式
    var update_CPU1 = function (res) { //res是json格式的response物件
        
        // 隱藏載入動畫
        CPU1.hideLoading();
        
        // 準備資料
        time.push(res.data[0]);
        cpu1.push(parseFloat(res.data[1]));
        if (time.length >= 10){
            time.shift();
            cpu1.shift();
        }
        
        // 填入資料
        CPU1.setOption({
            xAxis: {
                data: time
            },
            series: [{
                name: 'cpu1', // 根據名字對應到相應的系列
                data: cpu1
            }]
        });
        
    };
    
    //第二張echarts圖初始化
    var CPU2 = echarts.init(document.getElementById('CPU2'));
    CPU2.setOption({
        title: {
            text: 'CPU2'
        },
        tooltip: {},
        legend: {
            data:['cpu2']
        },
        toolbox: {
        show : true,
        feature : {
            mark : {show: true},
            dataView : {show: true, readOnly: false},
            magicType : {show: true, type: ['line', 'bar', 'stack', 'tiled']},
            restore : {show: true},
            saveAsImage : {show: true}
        }
    },
        calculable : true,
        xAxis: {
            data: []
        },
        yAxis: {},
        series: [{
            name: 'cpu2',
            type: 'line',
            smooth:true,
            itemStyle: {normal: {areaStyle: {type: 'default'}}},
            data: []
        }]
    });
        

    //準備好的 callback 函式
    var update_CPU2 = function (res) { //res是json格式的response物件
        
        // 隱藏載入動畫
        CPU2.hideLoading();
        
        // 準備資料
        time.push(res.data[0]);
        cpu2.push(parseFloat(res.data[2]));
        if (time.length >= 10){
            time.shift();
            cpu2.shift();
        }
        
        // 填入資料
        CPU2.setOption({
            xAxis: {
                data: time
            },
            series: [{
                name: 'cpu2', // 根據名字對應到相應的系列
                data: cpu2
            }]
        });
        
    };

    // 首次顯示載入動畫
    CPU1.showLoading();
    CPU2.showLoading();
    
    // 建立socket連線,等待伺服器“推送”資料,用回撥函式更新圖表
    $(document).ready(function() {
        namespace = '/test';
        var socket = io.connect(location.protocol + '//' + document.domain + ':' + location.port + namespace);
        
        socket.on('server_response', function(res) {
            update_CPU1(res);
            update_CPU2(res);
        });

    });
    
    </script>
</body>
</html>