psutil 的 cpu_percent 总是 returns 0.0
psutil's cpu_percent always returns 0.0
我希望我的 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 将始终 returns 0.0 cpu_percent:
$ 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()
这正确 returns 一个大于 0.0 的值。
只需全局定义 "p = psutil.Process()"(在 stat() 函数之外)。 cpu_percent() 自上次调用以来跟踪 CPU 次,这就是它能够确定百分比的方式。
第一次调用将始终为 0.0,因为计算百分比需要随时间比较两个值,因此,必须经过一些时间。
正如 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()
并提取您认为合理的时间段的价值。
Graham 的解决方案似乎可行,但我找到了一种更简单的解决方案,通过告诉它间隔,在这个例子中它测量最后一秒:
psutil.cpu_percent(interval=1)
我希望我的 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 将始终 returns 0.0 cpu_percent:
$ 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()
这正确 returns 一个大于 0.0 的值。
只需全局定义 "p = psutil.Process()"(在 stat() 函数之外)。 cpu_percent() 自上次调用以来跟踪 CPU 次,这就是它能够确定百分比的方式。
第一次调用将始终为 0.0,因为计算百分比需要随时间比较两个值,因此,必须经过一些时间。
正如 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()
并提取您认为合理的时间段的价值。
Graham 的解决方案似乎可行,但我找到了一种更简单的解决方案,通过告诉它间隔,在这个例子中它测量最后一秒:
psutil.cpu_percent(interval=1)