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



我正在寻找一种快速且轻巧的方式来从Python脚本读取系统正常运行时间。有没有办法从Python调用sysinfo 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

坦率地说,这似乎是一个更好的解决方案:

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

它还具有不需要任何其他模块的附加优势。

信用:来源

您可以尝试使用:

安装psutil
pip install psutil

然后使用以下代码片段:

import psutil
import time

def seconds_elapsed():
    return time.time() - psutil.boot_time()

print(seconds_elapsed())

我认为您不会比使用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

update

大部分时间都花在 libc中并创建缓冲区。如果您打算随着时间的推移反复拨打电话,则可以从功能中提取这些步骤,并仅测量系统调用。在这种情况下,该解决方案是明显的赢家:

uptime1: 5.066633300986723
uptime2: 0.11561189399799332
uptime3: 0.007740753993857652

tl; dr

简单,但不能保证是正常运行时间。应在Linux和Windows Vista 上代表正常运行时间,Python 3.3

time.monotonic()

https://docs.python.org/3/library/time.html#time.monotonic

更正确的Linux特异性,实际等效于Linux正常运行时间,Python 3.7

time.clock_gettime(time.CLOCK_BOOTTIME)

https://docs.python.org/3/library/time.html#time.clock_gettimehttps://docs.python.org/3/library/time.html#time.clock_boottime


长答案

没人提到简单的单调钟。posix从未指定的时间指定为单调的时钟,但Linux指定它是从boot

开始

在Linux上,Python在time.monotonic()中使用CLOCK_MONOTONIC

因此,获得正常运行时间就像调用

一样简单
import time
print(time.monotonic())

幸运的是,这也适用于许多其他平台(例如在Windows上使用GetTickCount64

CLOCK_MONOTONIC的问题是它不算深度睡眠。因此,您可以使用clock_boottime。这起作用的Linux内核可从2.6.39和3.7的Python上使用。/proc/uptime在内部使用ktime_get_boottime,即CLOCK_BOOTTIME时间尺度。所以1:1替换是这个。

import time
print(time.clock_gettime(time.CLOCK_BOOTTIME))

仅用于比较速度,它也是最快的。uptime1对我不起作用,因此仅测试其他变体

import time
import ctypes
import struct
libc = ctypes.CDLL('libc.so.6')
def uptime2():  
    with open('/proc/uptime', 'r') as f:
        uptime_seconds = float(f.readline().split()[0])
        return uptime_seconds
def uptime3():
    buf = ctypes.create_string_buffer(128)
    if libc.sysinfo(buf) != 0:
        return None
    uptime = struct.unpack_from('@l', buf.raw)[0]
    return uptime
uptime4 = time.monotonic
uptime5 = lambda: time.clock_gettime(time.CLOCK_BOOTTIME)
>>> print(timeit.timeit('ut.uptime2()', setup="import uptimecalls as ut", number=10000))
0.2356316399964271
>>> print(timeit.timeit('ut.uptime3()', setup="import uptimecalls as ut", number=10000))
0.05088816500210669
>>> print(timeit.timeit('ut.uptime4()', setup="import uptimecalls as ut", number=10000))
0.003676328000437934
>>> print(timeit.timeit('ut.uptime5()', setup="import uptimecalls as ut", number=10000))
0.012754358001984656

因此,它也是最快的解决方案。

添加最新答案。

这可能不是最快的方法。但这应该是psutil.boot_time()的替代品,因为我在Linux psutil Lib的最新版本中找不到boot_time

依赖:

pip3 install uptime

用法:

>>> from uptime import uptime
>>> uptime()
49170.129999999997

更多信息

在上一个上扩展,这将使您作为 datetime对象的系统正常运行时间:

from datetime import datetime, timedelta
def uptime():
    with open("/proc/uptime", "rb") as f:
        seconds = float(f.readline().split(maxsplit=1)[0])
        return datetime.now() - timedelta(seconds=seconds))
import os
print(os.times()[4])

python 2

os.times()
Return a 5-tuple of floating point numbers indicating accumulated (processor or other) times, in seconds. The items are: user time, system time, children’s user time, children’s system time, and elapsed real time since a fixed point in the past, in that order. See the Unix manual page times(2) or the corresponding Windows Platform API documentation. On Windows, only the first two items are filled, the others are zero.
https://docs.python.org/2/library/os.html

python 3

os.times()
Returns the current global process times. The return value is an object with five attributes:
user - user time
system - system time
children_user - user time of all child processes
children_system - system time of all child processes
elapsed - elapsed real time since a fixed point in the past
For backwards compatibility, this object also behaves like a five-tuple containing user, system, children_user, children_system, and elapsed in that order.
See the Unix manual page times(2) and times(3) manual page on Unix or the GetProcessTimes MSDN on Windows. On Windows, only user and system are known; the other attributes are zero.
Availability: Unix, Windows.
Changed in version 3.3: Return type changed from a tuple to a tuple-like object with named attributes.
https://docs.python.org/3/library/os.html

最新更新