在Linux中使用Python获得系统正常运行时间的最快方法


问题内容

我正在寻找一种快速,轻量级的方法来从Python脚本读取系统正常运行时间。有没有办法sysinfo从Python调用Linux系统调用?

到目前为止,我发现了另外两种测量正常运行时间的方法,一种涉及运行外部进程,另一种涉及读取中的文件/proc

import subprocess

def uptime1():
    raw = subprocess.check_output('uptime').decode("utf8").replace(',', '')
    days = int(raw.split()[2])
    if 'min' in raw:
        hours = 0
        minutes = int(raw[4])
    else:
        hours, minutes = map(int,raw.split()[4].split(':'))
    totalsecs = ((days * 24 + hours) * 60 + minutes) * 60
    return totalsecs

def uptime2():  
    with open('/proc/uptime', 'r') as f:
        uptime_seconds = float(f.readline().split()[0])
        return uptime_seconds

比较速度时,第二种方法快了大约50倍。尽管如此,直接调用系统调用还是要好一个数量级。

>> import timeit
>> print(timeit.timeit('ut.uptime1()', setup="import uptimecalls as ut", number=1000))
1.7286969429987948
>> print(timeit.timeit('ut.uptime2()', setup="import uptimecalls as ut", number=1000))
0.03355383600865025

问题答案:

我认为您不会比使用ctypes调用更快,sysinfo()但是在我的测试中,它比/ proc慢。那些linux系统程序员似乎知道他们在做什么!

import ctypes
import struct

def uptime3():
    libc = ctypes.CDLL('libc.so.6')
    buf = ctypes.create_string_buffer(4096) # generous buffer to hold
                                            # struct sysinfo
    if libc.sysinfo(buf) != 0:
        print('failed')
        return -1

    uptime = struct.unpack_from('@l', buf.raw)[0]
    return uptime

在运行缓慢的笔记本电脑上运行您的两个测试以及我的测试,我得到了:

>>> print(timeit.timeit('ut.uptime1()', setup="import uptimecalls as ut", number=1000))
5.284219555993332
>>> print(timeit.timeit('ut.uptime2()', setup="import uptimecalls as ut", number=1000))
0.1044210599939106
>>> print(timeit.timeit('ut.uptime3()', setup="import uptimecalls as ut", number=1000))
0.11733305400412064

更新

大部分时间都花在拉入libc和创建缓冲区上。如果您计划随着时间的推移反复进行调用,则可以将这些步骤从功能中撤出并仅测量系统调用。在这种情况下,此解决方案无疑是赢家:

uptime1: 5.066633300986723
uptime2: 0.11561189399799332
uptime3: 0.007740753993857652