如何使用 Python 从 fio 捕获非阻塞实时输出

How to capture non-blocking realtime output from fio using Python

>>>x = subprocess.Popen(["fio", "--filename=/dev/sdd", "--name=job1", "--numjobs=2"], stdout=subprocess.PIPE)

但我需要实时捕捉 fio 进程。我虽然在做线程 subprocess.stdout.readline,但它似乎没有更新性能数据:

>>> x = subprocess.Popen(["fio", "--filename=/dev/sdd", "--name=job1", "--numjobs=2"], stdout=subprocess.PIPE)

>>> x.stdout.readline()  
'job1: (g=0): rw=read, bs=4K-4K/4K-4K/4K-4K, ioengine=sync, iodepth=1\n'

>>> x.stdout.readline()  
'...\n'

>>> x.stdout.readline()  
'fio-2.2.11\n'

>>> x.stdout.readline()  
'Starting 2 processes\n'

>>> x.stdout.readline()  

它只是在这之后挂起。

fio 的命令行执行如下所示:

[root@goblinbank tmp]# fio --filename=/dev/sdd --name=job1 --numjobs=2
job1: (g=0): rw=read, bs=4K-4K/4K-4K/4K-4K, ioengine=sync, iodepth=1
...
fio-2.2.11
Starting 2 processes
Jobs: 2 (f=2): [R(2)] [0.2% done] [246.3MB/0KB/0KB /s] [63.5K/0/0 iops] [eta 02h:26m:09s]

"Jobs: 2 (f=2): [R(2)]"之后的文字不断刷新为新值

然后您可以使用 fcntl 将其设置为非阻塞 IO,如果数据不可读取,它将引发异常。只需添加:

fcntl.fcntl(process.stdout.fileno(), fcntl.F_SETFL, os.O_NONBLOCK)

创建流程后,使用 try/except IOError 子句验证是否有可读内容,如下所示:

import fcntl
import os
import shlex
import subprocess
import time

cmd = 'fio --filename=/home/turicas/data/test.tmp --name=job1 --numjobs=2'
process = subprocess.Popen(shlex.split(cmd), stdout=subprocess.PIPE)
fcntl.fcntl(process.stdout.fileno(), fcntl.F_SETFL, os.O_NONBLOCK)

data = None
while data != '':
    try:
        data = process.stdout.readline()
    except IOError:
        print 'no data. waiting...'
        time.sleep(0.1)  # wait stdout output to be available
    else:
        print 'data read:', data
print 'stdout closed'

这解决了问题:

x = subprocess.Popen(["fio", "--filename=/dev/sdd", "--name=job1", "--numjobs=2", "--eta=always"], stdout=subprocess.PIPE, universal_newlines=True)

注意 fio 中的 --eta=always 标志和 Popen 中的 universal_newlines=True 参数。

更多信息here