V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
推荐学习书目
Learn Python the Hard Way
Python Sites
PyPI - Python Package Index
http://diveintopython.org/toc/index.html
Pocoo
值得关注的项目
PyPy
Celery
Jinja2
Read the Docs
gevent
pyenv
virtualenv
Stackless Python
Beautiful Soup
结巴中文分词
Green Unicorn
Sentry
Shovel
Pyflakes
pytest
Python 编程
pep8 Checker
Styles
PEP 8
Google Python Style Guide
Code Style from The Hitchhiker's Guide
mingwiki
V2EX  ›  Python

Python 使用 psutil 计算网速和显示进程,如何提高并发?

  •  
  •   mingwiki ·
    mingwiki · 19 天前 · 1953 次点击

    我刚开始学 fastapi ,写了一些简单的接口,不想搞 netdata 或者 glances 之类的复杂界面,想把服务器基本的参数服务之类的的直接显示在接口里,其中计算网速和显示进程部分严重拖累性能,qps 仅为个位数,不知道异步怎么写,有什么改进的方案,请各位大佬指导一下谢谢。

    计算网速,用了 asyncio 但是并发不高,qps 个位数。

    async def calculate_network_speed():
        initial_time = time.time()
        initial_bytes_sent = psutil.net_io_counters().bytes_sent
        initial_bytes_recv = psutil.net_io_counters().bytes_recv
        await asyncio.sleep(1)
        current_bytes_sent = psutil.net_io_counters().bytes_sent
        current_bytes_recv = psutil.net_io_counters().bytes_recv
        elapsed_time = time.time() - initial_time
        download_speed = (current_bytes_recv - initial_bytes_recv) / elapsed_time
        upload_speed = (current_bytes_sent - initial_bytes_sent) / elapsed_time
        return download_speed, upload_speed
    

    显示进程,用的同步,写了个装饰器按时间 cache 结果,qps50 左右也不高。

    @time_cache(5)
    def get_top_processes(slice: int = 10):
        processes = [
            (
                proc.info["pid"],
                proc.info["name"],
                proc.info["cpu_percent"],
                proc.info["memory_percent"],
                " ".join(proc.info["cmdline"]),
            )
            for proc in psutil.process_iter(
                ["pid", "name", "cpu_percent", "memory_percent", "cmdline"]
            )
            if proc.info["cpu_percent"] > 0 or proc.info["memory_percent"] > 0
        ]
        top_cpu = sorted(processes, key=lambda x: x[2], reverse=True)[:slice]
        top_mem = sorted(processes, key=lambda x: x[3], reverse=True)[:slice]
        return top_cpu, top_mem
    
    def time_cache(max_age=10, maxsize=128, typed=False):
        def decorator(fn):
            @lru_cache(maxsize=maxsize, typed=typed)
            def _new(*args, __time_salt, **kwargs):
                return fn(*args, **kwargs)
    
            @wraps(fn)
            def wrapped(*args, **kwargs):
                return _new(*args, **kwargs, __time_salt=int(time.time() / max_age))
    
            return wrapped
    
        return decorator
    

    我的网站显示如下:https://api.naizi.fun/status 安装浏览器插件自动格式化一下就行了。请大佬说说 python 异步咋写,有没有好的参考?

    24 条回复    2024-04-12 20:24:01 +08:00
    BBBPineapple
        1
    BBBPineapple  
       19 天前
    可以试试将内容作为全局变量,单独用一个线程去更新这个变量。接口直接返回全局变量的内容即可
    mingwiki
        2
    mingwiki  
    OP
       19 天前
    @BBBPineapple #1 我一开始就是这么想的,用全局变量或者 redis mq 之类的存着,单独跑个 schedule 每秒更新,但是感觉怪怪的,我觉得是自己水平不行没办法写的更优雅。不知道 asyncio 是不是这么用的,为啥 qps 那么低我没想明白。
    shinession
        3
    shinession  
       19 天前
    OP 这个域名好强大
    mingwiki
        4
    mingwiki  
    OP
       19 天前
    @shinession #3 一般吧 我挂了 1000 块都没人要
    keakon
        5
    keakon  
       19 天前
    1. psutil.net_io_counters() 可以保存成一个变量,同时拿 bytes_sent 和 bytes_recv
    2. 并发的请求在没有获得响应前,不会被缓存,因此都会进入 await asyncio.sleep(1)
    3. psutil.process_iter 需要遍历 /proc 来获取所有 pid ,这里存在磁盘 IO 和系统调用,没有异步执行,但是要改的话会很麻烦,我一般都不用 psutil:
    import asyncio
    import aiofiles.os

    async def list_dir(path):
    ----print(await aiofiles.os.listdir(path))

    asyncio.run(list_dir('.'))
    sohusi
        6
    sohusi  
       19 天前
    单独用一个异步死循环计算,接口直接取数据。循环内部用 asyncio.sleep 等待,就不用怕阻塞事件循环,甚至不需要锁来同步
    rrfeng
        7
    rrfeng  
       19 天前
    进程多的情况下 ps 命令也很慢。psutil 应该也差不多,都是读 /proc 计算。
    zhuisui
        8
    zhuisui  
       19 天前
    渲染和计算分离
    mingwiki
        9
    mingwiki  
    OP
       19 天前
    @keakon #5 感谢大佬,请问第二条异步怎么改呢有没有参考代码?第三条意思好像是需要自行写一个异步版 psutil 我先研究研究
    Hopetree
        10
    Hopetree  
       19 天前
    你这还是在 Linux 上面运行,如果你换成 Windows 会更低,更慢。我们之前采集服务用进程采集就遇到过类似的情况,特别是 Windows 上面有时候直接卡死,因为要过滤掉一些系统进程,有两个建议:1.使用黑名单过滤一些系统进程,2.只显示自己要的字段,可参考下面我之前进行服务采集的片段


    ![]( https://tendcode.com/cdn/2024/04/202404101654151.png)
    mingwiki
        11
    mingwiki  
    OP
       19 天前
    @Hopetree #10 感谢大佬
    Pters
        12
    Pters  
       19 天前
    可以参考 moviepilot 项目,他就是 fastapi 写的有网速,进程等
    noahlias
        13
    noahlias  
       19 天前
    @Pters 搜了一下并没有机器的网络和 io 有个进程
    https://github.com/search?q=repo%3Ajxxghp%2FMoviePilot%20psutil.&type=code
    LeeReamond
        14
    LeeReamond  
       19 天前
    psutil.net_io_counters 有没有系统调用或者 IO 行为,它是同步的还是异步的,你用 asyncio 和速度变快有任何关系吗?
    MoYi123
        15
    MoYi123  
       19 天前
    cache 里不要按调用次数缓存, 改成每秒更新一次就行吧.

    还有算 topn 可以用 heap, 虽然这点应该没多大影响.
    kneo
        16
    kneo  
       19 天前 via Android
    先看下 CPU 占用是 usr 还是 sys 。
    so1n
        17
    so1n  
       19 天前
    asyncio.to_thread
    mingwiki
        18
    mingwiki  
    OP
       19 天前
    @kneo #16 cpu 占用很低,几乎没啥起伏。
    Alliot
        19
    Alliot  
       19 天前
    循环间隔固定时间去获取数据存变量里,然后请求直接读变量返回。
    kneo
        20
    kneo  
       19 天前
    @mingwiki 注意看下系统调用的时间。top 里的 sy 列。或者 time 执行结果。
    mingwiki
        21
    mingwiki  
    OP
       19 天前
    @kneo #20 只有 python 和 uvicorn 占用 cpu ,没有磁盘读写,没有其他的系统进程占用
    kneo
        22
    kneo  
       19 天前
    @mingwiki 我说的是“系统调用”。
    GeruzoniAnsasu
        23
    GeruzoniAnsasu  
       19 天前
    @mingwiki #1 的方向就是对的。 取样是个很慢的操作。 你需要单独一个允许 block 的 routine 来处理取样周期。

    而且在 linux 里大部分的「系统信息」相关的实现最后都会退化成读 procfs / sysfs 之类的,大家都不喜欢自找麻烦去调系统 API 再自己去转换那些结构/枚举/字符串…… 所以

    不管什么实现都一样慢。你能做的只有把取样和查询隔离开。
    julyclyde
        24
    julyclyde  
       17 天前
    这事就提高不了
    因为有几个参数需要多次取样然后相减
    间隔时间不能太短
    关于   ·   帮助文档   ·   博客   ·   API   ·   FAQ   ·   我们的愿景   ·   实用小工具   ·   951 人在线   最高记录 6543   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 25ms · UTC 21:43 · PVG 05:43 · LAX 14:43 · JFK 17:43
    Developed with CodeLauncher
    ♥ Do have faith in what you're doing.