如何衡量Python的asyncio代码性能?

e-s*_*tis 12 python trace performance-testing python-asyncio

我不能使用常规工具和技术来测量协程的性能,因为它await不应该考虑它所花费的时间(或者它应该只考虑从等待但不是IO延迟读取的开销).

那么如何衡量协程所需的时间呢?我如何比较2个实现并找到更高效的?我使用什么工具?

Vin*_*ent 15

一种方法是修补__CODE__以便计时并保存所有IO操作.这可以使用上下文管理器完成:

import time

real_time = time.time()
cpu_time = time.process_time()

time.sleep(1.)
sum(range(10**6))

real_time = time.time() - real_time
cpu_time = time.process_time() - cpu_time

print(f"CPU time: {cpu_time:.2f} s, Real time: {real_time:.2f} s")
Run Code Online (Sandbox Code Playgroud)

然后使用另一个上下文管理器为完整运行计时,并计算总时间和IO时间之间的差异:

$ /usr/bin/time -f "CPU time: %U s, Real time: %e s" python demo.py
CPU time: 0.02 s, Real time: 1.02 s  # python output
CPU time: 0.03 s, Real time: 1.04 s  # `time` output
Run Code Online (Sandbox Code Playgroud)

这是一个简单的例子:

async def main():
    print("~ Correct IO management ~")
    with print_timing():
        await asyncio.sleep(1)
        sum(range(10**6))
    print()

    print("~ Incorrect IO management ~")
    with print_timing():
        time.sleep(0.2)
        await asyncio.sleep(0.8)
        sum(range(10**6))
    print()

asyncio.set_event_loop_policy(TimedEventLoopPolicy())
asyncio.run(main(), debug=True)
Run Code Online (Sandbox Code Playgroud)

它打印以下报告:

~ Correct IO management ~
CPU time:      0.016 s
Select time:   1.001 s
Other IO time: 0.000 s
Real time:     1.017 s

~ Incorrect IO management ~
CPU time:      0.016 s
Select time:   0.800 s
Other IO time: 0.200 s
Real time:     1.017 s
Run Code Online (Sandbox Code Playgroud)

编辑

另一种方法是子类化__CODE__并覆盖该__CODE__方法以计算步骤的执行时间:

Executing <Handle <TaskWakeupMethWrapper object at 0x7fd4835864f8>(<Future finis...events.py:396>) created at ~/miniconda/lib/python3.7/asyncio/futures.py:288> took 0.243 seconds
Run Code Online (Sandbox Code Playgroud)

然后可以将子类注册为默认任务工厂:

import time

real_time = time.time()
cpu_time = time.process_time()

time.sleep(1.)
sum(range(10**6))

real_time = time.time() - real_time
cpu_time = time.process_time() - cpu_time

print(f"CPU time: {cpu_time:.2f} s, Real time: {real_time:.2f} s")
Run Code Online (Sandbox Code Playgroud)

同样的例子:

$ /usr/bin/time -f "CPU time: %U s, Real time: %e s" python demo.py
CPU time: 0.02 s, Real time: 1.02 s  # python output
CPU time: 0.03 s, Real time: 1.04 s  # `time` output
Run Code Online (Sandbox Code Playgroud)

随着输出:

async def main():
    print("~ Correct IO management ~")
    with print_timing():
        await asyncio.sleep(1)
        sum(range(10**6))
    print()

    print("~ Incorrect IO management ~")
    with print_timing():
        time.sleep(0.2)
        await asyncio.sleep(0.8)
        sum(range(10**6))
    print()

asyncio.set_event_loop_policy(TimedEventLoopPolicy())
asyncio.run(main(), debug=True)
Run Code Online (Sandbox Code Playgroud)