psutil的cpu_percent总是返回0.0

时间:2016-11-27 00:38:09

标签: flask monitoring metrics psutil

我希望我的Flask应用程序以百分比的形式报告当前使用的CPU和内存:

import psutil
from flask import Flask, request, jsonify

app = Flask(__name__)

@app.route("/test", methods=["GET"])
def healthz():
    return jsonify(msg="OK"), 200

@app.route("/stats", methods=["GET"])
def stats():
    p = psutil.Process()
    json_body = {
        "cpu_percent": p.cpu_percent(interval=None),
        "cpu_times": p.cpu_times(),
        "mem_info": p.memory_info(),
        "mem_percent": p.memory_percent()
    }
    return jsonify(json_body), 200


def main():
    app.run(host="0.0.0.0", port=8000, debug=False)

if __name__ == '__main__':
    main()

在向/ test发送大量请求时,/ stats将始终为cpu_percent返回0.0:

$ while true; do curl http://127.0.0.1:8000/test &>/dev/null; done &
$ curl http://127.0.0.1:8000/stats
{
  "cpu_percent": 0.0, 
  "cpu_times": [
    4.97, 
    1.28, 
    0.0, 
    0.0
  ], 
  "mem_info": [
    19652608, 
    243068928, 
    4292608, 
    4096, 
    0, 
    14675968, 
    0
  ], 
  "mem_percent": 1.8873787935409003
}

但是,如果我使用ipython手动检查:

import psutil
p = psutil.Process(10993)
p.cpu_percent()

这正确返回大于0.0的值。

2 个答案:

答案 0 :(得分:2)

只需在全局范围内定义“p = psutil.Process()”(在stat()函数之外)。 cpu_percent()跟踪自上次调用以来的CPU时间,这就是它如何确定百分比。

第一次调用将始终为0.0,因为计算百分比需要随时间比较两个值,因此,必须经过一段时间。

答案 1 :(得分:2)

正如Giampaolo指出的那样,Process的实例需要处于全局范围,因为实例会根据先前的调用跟踪状态以进行处理。

请注意,虽然CPU百分比可以从一个时刻到另一个时刻跳得很多,特别是在计算的时间段不断变化的情况下,可能会非常混乱。使用后台线程可能会更好,它可以在设定的时间范围内计算出CPU百分比平均值。

我碰巧使用的一些代码可能很有用:

from __future__ import print_function

import os
import time
import atexit

import threading

try:
    import Queue as queue
except ImportError:
    import queue

import psutil

_running = False
_queue = queue.Queue()
_lock = threading.Lock()

_cpu_percentage = 1800 * [0.0]
_processes = {}

def _monitor():
    global _cpu_percentage
    global _processes

    while True:
        marker = time.time()

        total = 0.0
        pids = psutil.pids()

        processes = {}

        for pid in pids:
            process = _processes.get(pid)
            if process is None:
                process = psutil.Process(pid)
            processes[pid] = process
            total += process.cpu_percent()

        _processes = processes

        _cpu_percentage.insert(0, total)

        _cpu_percentage = _cpu_percentage[:1800]

        duration = max(0.0, 1.0 - (time.time() - marker))

        try:
            return _queue.get(timeout=duration)

        except queue.Empty:
            pass

_thread = threading.Thread(target=_monitor)
_thread.setDaemon(True)

def _exiting():
    try:
        _queue.put(True)
    except Exception:
        pass
    _thread.join()

def track_changes(path):
    if not path in _files:
        _files.append(path)

def start_monitor():
    global _running
    _lock.acquire()
    if not _running:
        prefix = 'monitor (pid=%d):' % os.getpid()
        print('%s Starting CPU monitor.' % prefix)
        _running = True
        _thread.start()
        atexit.register(_exiting)
    _lock.release()

def cpu_averages():
    values = _cpu_percentage[:60]

    averages = {}

    def average(secs):
        return min(100.0, sum(values[:secs])/secs)

    averages['cpu.average.1s'] = average(1)
    averages['cpu.average.5s'] = average(5)
    averages['cpu.average.15s'] = average(15)
    averages['cpu.average.30s'] = average(30)
    averages['cpu.average.1m'] = average(60)
    averages['cpu.average.5m'] = average(300)
    averages['cpu.average.15m'] = average(900)
    averages['cpu.average.30m'] = average(1800)

    return averages

我有其他的东西,我删除了,所以希望剩下的东西仍处于可用状态。

要使用它,请添加到文件monitor.py,然后导入主文件中的模块并启动监控循环。

import monitor
monitor.start_monitor()

然后在每个请求呼叫上:

monitor.cpu_averages()

并提取您认为有意义的时间段的值。