Python后台进程内存使用情况监控-Windows/Linux

服务器运行时,监控各个客户端或服务器进程的内存使用情况可以了解各进程的内存占用情况,方便排查到具体进程的问题。

Windows


文件名:monitor.py

监控程序可以直接运行。各功能块功能已详细注释,更详细的解释可以查看文末参考博客,主要将同名的各个Python进程的占用情况全部监控,并将信息写入csv文件中。

"""
进程监控程序 for windows
python monitor.py --name test1
author: cyg
"""

import datetime
import os.path
import argparse
import psutil
import time
import pandas as pd


# 获取电脑整体的CPU、内存占用情况
def getMemory():
    """
    Obtain the system memory usage
    """
    data = psutil.virtual_memory()
    memory = str(int(round(data.percent))) + "%"
    print("系统整体memory占用:" + memory)
    return memory


def getCpu():
    """
    count each cpu usage's average
    return: average cpu usage
    """
    cpu_list = psutil.cpu_percent(percpu=True)
    average_cpu = round(sum(cpu_list) / len(cpu_list), 2)
    cpu = str(average_cpu) + "%"
    print("系统各整体cpu平均占用:" + cpu)
    return cpu


# 获取指定进程的CPU和内存占用信息代码
def getMemSize(pid):
    """
    get each pid memory
    """
    # 根据进程号来获取进程的内存大小
    process = psutil.Process(pid)
    memInfo = process.memory_info()

    # rss: 该进程实际使用物理内存(包含共享库占用的全部内存)。
    # vms:该进程使用的虚拟内存总量。

    return memInfo.rss / 1024 / 1024


def getCpuPercent(pid):
    """
    get each pid cpu usage percent
    """
    # 根据进程号来获取进程的内存大小
    p = psutil.Process(pid)
    p_cpu = p.cpu_percent(interval=0.1)
    cpu = round(p_cpu, 2)
    return cpu


def getTotalM(processName, python_process):
    """
    processName: cmp_server.py
    python_process: 全体(pid, name)元组列表集和
    [(124, 'cmp_server.py'), (234, 'cmp_server.py'),(3452, 'monitor.py')]
    """
    # 一个进程名对应的可能有多个进程
    # 进程号才是进程的唯一标识符,进程名不是
    totalM = 0
    for pid, name in python_process:
        if name == processName:
            totalM += getMemSize(pid)
    print(f'{processName}进程占用内存:%.2f MB' % totalM)
    finalM = round(totalM, 2)
    return finalM


def getTotalCPU(processName, python_process):
    """
    processName: cmp_server.py
    python_process: 全体(pid, name)元组列表集和
    [(124, 'cmp_server.py'), (234, 'cmp_server.py'),(3452, 'monitor.py')]
    """
    # 一个进程名对应的可能有多个进程
    # 进程号才是进程的唯一标识符,进程名不是
    totalCPU = 0
    for pid, name in python_process:
        if name == processName:
            totalCPU += getCpuPercent(pid)
    totalCPU_convert = round(totalCPU, 2)
    finalCPU = str(totalCPU_convert) + '%'
    print(f"{processName}进程占用CPU:" + finalCPU)
    return totalCPU_convert


# 将测试结果数据写入csv文件
def writeExcel(caseName, cpu, mem, processcpu, processmem, filename) -> None:
    """
    All same name process which like 2 python process called 'cmp_server.py' will not be separate.
    :param caseName: cmp_server.py
    :param cpu: sys average cpu
    :param mem: sys memory
    :param processcpu: total cpu for process of the same name like 'cmp_server.py'
    :param processmem: total mem for process of the same name like 'cmp_server.py'
    :param filename: the name of csv
    """
    timestamp = time.strftime('%Y-%m-%d-%H:%M:%S', time.localtime(time.time()))
    dict = {'caseName': [caseName], 'Sys_CPU': [cpu], 'Sys_Memory': [mem],
            'Pycharm_Cpu': [processcpu], 'Pycharm_Mem': [processmem],
            'OperationTime': [timestamp]}

    # 字典中的key值即为csv中列名
    dataframe = pd.DataFrame(dict)
    dataframe['OperationTime'] = pd.to_datetime(dataframe['OperationTime'])
    csv_file = f"{filename}_monitor.csv"

    if not os.path.exists(csv_file):
        dataframe.to_csv(csv_file, date_format='%Y-%m-%d-%H:%M:%S',
                         mode='a', index=False, header=True, encoding='GBK')
    else:
        # 将DataFrame存储为csv, mode='a'表示每一次都是追加内容而不是覆盖,header=False表示不写列名
        dataframe.to_csv(csv_file, date_format='%Y-%m-%d-%H:%M:%S',
                         mode='a', index=False, header=False, encoding='GBK')


# 封装方法为函数,以便后续直接调用
def getCpuAndMem(caseName, info, filename):
    """
    caseName: 传入的不重复的.py文件名
    info: 全体pid和name的元组列表
    filename: csv文件名
    """
    memory = getMemory()
    cpu = getCpu()
    # 获取pycharm64.exe进程占用的CPU和内存
    processmem = getTotalM(caseName, info)
    processcpu = str(getTotalCPU(caseName, info)) + '%'

    writeExcel(caseName, cpu, memory, processcpu, processmem, filename)
    print(f"{caseName}进程_CPU占用:%s  {caseName}进程内存占用:%s MB" % (processcpu, processmem))
    print("===============================================================")

def query_process(process_name):
    """
    output current python process info
    """
    init_name = set()
    python_process = []
    for proc in psutil.process_iter():
        if process_name in proc.name():
            # print("-------", proc.cmdline())
            try:
                for process in proc.cmdline()[1:]:  # 第一个肯定是Python,故跳过
                    if len(process) >= 7:
                        if '/' in process:
                            name = process.split('/')[-1]
                        elif '\\' in process:
                            name = process.split('\\')[-1]
                        else:
                            name = process
                        break
                python_process.append((proc.pid, name))
                init_name.add(name)
            except:
                import traceback
                traceback.print_exc()
    return python_process, init_name

if __name__ == '__main__':
    # python_process, name_list = query_process('python')
    # print(python_process, name_list)
    parser = argparse.ArgumentParser()
    parser.add_argument('--name', type=str, default='test', help='inital csv name')
    args = parser.parse_args()
    print(f'chose filename_{args.name}')

    continue_loop = True
    while continue_loop:
        t0 = time.time()
        python_process, name_list = query_process('python')  # 监控所有python进程状态
        print(f'The name_list is {name_list}')
        if len(name_list) == 1 and 'monitor.py' in name_list:
            print('no python process!')
            continue_loop = False
        else:
            name_list.discard('monitor.py')
            for name in name_list:
                getCpuAndMem(caseName=name, info=python_process, filename=args.name)
            time.sleep(60)  # 一分钟监控一次
        t1 = time.time()
        print(f'spend {round(t1-t0, 2)}s')

Linux 

说明:和Windows完全一致,Linux输入以下指令可以后台运行 ,若遇其他问题可以边运行边调试,欢迎交流讨论。

nohup python -u monitor.py --name test > test.log 2>&1 &


运行结果展示


参考博客:Python神器:psutil库使用详解

  • 1
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值