下面的小代码片段显示了一串数字相加所需的时间.

import gc
from time import process_time_ns

gc.disable() # disable garbage collection
for func in [
    process_time_ns,
]:
    pre = func()

    s = 0
    for a in range(100000):
        for b in range(100):
            s += b
    print(f"sum: {s}")

    post = func()
    delta_s = (post - pre) / 1e9 # difference in seconds
    print(f"{func}: {delta_s}")

令我惊讶的是,在停靠容器中运行时(~1.6s)比在主机上直接运行时(~0.8s)花费的时间要长得多. 经过一番挖掘,我发现docker的一些安全功能可能会导致速度变慢(https://betterprogramming.pub/faster-python-in-docker-d1a71a9b9917,https://pythonspeed.com/articles/docker-performance-overhead/).实际上,添加docker参数--privileged只会使它的运行时间减少约0.9s. 然而,我仍然对我观察到的这个~0.1s的差距感到困惑,这一差距没有在文章中体现出来. 我已经将我的CPU频率设置为3000 MHz,并修复了在内核0上运行的python执行.

每项测量30次的统计数据:

local docker --privileged docker
avg 0.79917586 0.904496884 1.61980727
std 0.02433539 0.031948695 0.04034594
min 0.78087375 0.867265714 1.56995282
q1 0.78211388 0.880717119 1.58672566
q2 0.79006154 0.895180195 1.61322376
q3 0.80732969 0.916945585 1.64363027
max 0.89824817 1.012580084 1.72252714

对于测量,使用了以下命令:

  • 本地:taskset -c 0 python3 main.py
  • docker --特权:taskset -c 0 docker run --privileged --rm -w /data -v /home/slammer/Projects/timing-python-inside-docker:/data -it python:3 python main.py
  • docker :taskset -c 0 docker run --rm -w /data -v /home/slammer/Projects/timing-python-inside-docker:/data -it python:3 python main.py

是什么原因导致头顶上有剩余的 docker ? 可以减轻它以实现裸机性能吗?

编辑:在Linux MINT 20.3主机(内核:x86_64 Linux 5.4.0-117-通用)上进行测量;扩展坞版本:20.10.17

推荐答案

速度减慢似乎不是由docker引起的,而是由python二进制代码的差异造成的.

我将docker映像python:3中打包的python复制到我的主机(将docker的/usr/local复制到我的Hosts docker-python文件夹). 然后,我使用以下命令再次运行相同的基准测试,使用此二进制文件:LD_LIBRARY_PATH=docker-python/local/lib taskset -c 0 docker-python/local/bin/python3.10 main.py 瞧,使用此"docker二进制"的测量结果与使用"docker--Priviled"测量的结果相同(在测量误差范围内):

local dockerbinary docker --privileged docker
avg 0.79917586 0.89829016 0.904496884 1.61980727
std 0.02433539 0.03554546 0.031948695 0.04034594
min 0.78087375 0.86344007 0.867265714 1.56995282
q1 0.78211388 0.86950620 0.880717119 1.58672566
q2 0.79006154 0.88853465 0.895180195 1.61322376
q3 0.80732969 0.91612282 0.916945585 1.64363027
max 0.89824817 0.99477790 1.012580084 1.72252714

谜团解开:)


那么,这两个二进制文件有什么不同呢? 据我所知,docker附带的二进制代码是with debug_info, not stripped,而我的本地二进制代码只有stripped.

$ file `which python3.10`
/usr/bin/python3.10: ELF 64-bit LSB executable, x86-64, version 1 (SYSV), dynamically linked, interpreter /lib64/ld-linux-x86-64.so.2, BuildID[sha1]=fb3f4369481251e6ba441382fd6d9ab47af0db29, for GNU/Linux 3.2.0, stripped
$ file docker-python/local/bin/python3.10
docker-python/local/bin/python3.10: ELF 64-bit LSB shared object, x86-64, version 1 (SYSV), dynamically linked, interpreter /lib64/ld-linux-x86-64.so.2, BuildID[sha1]=618b23f947f202224f4ea8e16375ac7bcad13c4f, for GNU/Linux 3.2.0, with debug_info, not stripped

我的猜测是,with debug_info编译引入了大约11%的性能开销. 如果这是正确的,它会提示下一个问题"如果默认的停靠器图像导致如此显著的速度减慢,为什么它会使用这个二进制文件?" 对于这一点,我目前还没有回答(而且这个猜测可能完全错误).

交叉链接:https://github.com/docker-library/python/issues/825

Python相关问答推荐

ValueRight:参数目标和输出必须具有相同的形状.接收:目标.形状=(无,512),输出.形状=(无,3)

Python中的锁定类和线程以实现dict移动

在Python中根据id填写年份系列

如何才能将每个组比上一组增加N %?

按 struct 值对Polars列表[struct[]]排序

Tkinter -控制调色板的位置

如何在PIL、Python中对图像应用彩色面膜?

数字梯度的意外值

比较两个二元组列表,NP.isin

为什么tkinter框架没有被隐藏?

非常奇怪:tzLocal.get_Localzone()基于python3别名的不同输出?

如何在python xsModel库中定义一个可选[December]字段,以产生受约束的SON模式

通过pandas向每个非空单元格添加子字符串

Odoo 16使用NTFS使字段只读

给定高度约束的旋转角解析求解

Django RawSQL注释字段

pysnmp—lextudio使用next()和getCmd()生成器导致TypeError:tuple对象不是迭代器''

提高算法效率的策略?

如何按row_id/row_number过滤数据帧

处理Gekko的非最优解