为什么我的函数比 python 的 IDLE 打印函数快?

Why is my function faster than python's print function in IDLE?

我前阵子写过这个函数:

def faster_print(*args, sep=" ", end="\n", file=stdout):
    file.write(sep.join(map(str, args))+end)

我测试了它:

from sys import stdout
from time import perf_counter

def faster_print(*args, sep=" ", end="\n", file=stdout):
    file.write(sep.join(map(str, args))+end)

def time(function, *args, **kwargs):
    start = perf_counter()
    function(*args, **kwargs)
    return perf_counter()-start

def using_normal_print(number):
    for i in range(number):
        print("Hello world.", 5, 5.0, ..., str)

def using_faster_print(number):
    for i in range(number):
        faster_print("Hello world.", 5, 5.0, ..., str)

normal_time = time(using_normal_print, number=100)
faster_time = time(using_faster_print, number=100)

print("Normal print:", normal_time)
print("My print function", faster_time)

事实证明,它只是在 IDLE 中更快,而不是 cmd。我知道 IDLE 为 sys.stdoutsys.stdinsys.stderr 创建了自己的对象,但我不明白为什么它只会减慢 python 的内置 print ] 功能。 回答说内置的 print 函数是用 c 语言编写的。这不应该让它更快,因为我的函数需要从 python 字节码编译成机器码吗?

我正在使用 Python 3.7.9 和 IDLE 版本 3.7.9

TheLizard,感谢您报告和修改您的实验。作为 IDLE 维护者,我很关心 IDLE 速度。我注意到打印到屏幕有时比 Python terminal/console REPL 慢得多。在后者中,Python 与屏幕 window 在同一进程中执行,而 screen.write 直接写入屏幕缓冲区。另一方面,IDLE 在单独的进程中执行用户代码。在那个过程中,替换 sys.stdout 通过套接字将输出发送到 IDLE GUI 进程,然后调用 tkinter text.insert,后者调用 tcl/tk 写入屏幕错误的函数。但是直到现在,我还没有好好调查过。

我 运行 你的代码在我的 Win 10 机器上的 3.10.0a5 中。在 REPL 中,正常和快速打印耗时 0.05 秒。在 IDLE 中,他们花费了大约 1.1 秒和 0.3 秒。上面的开销解释了因子 6 (.3/.05)。但是附加系数大约3.7(1.1/.3)?

为了检验 kaya3 的第二个假设,我定义了 s = 'a'*75 并将您的打印参数替换为 s。在 REPL 中,时间仍然是 .05 和 .05。在 IDLE 中,它们大约为 .41 和 .31。我得出的结论是,内部打印功能有一些开销,但 3.7 的大部分是额外的套接字到屏幕开销。当 print 正在写入缓冲区时,没有理由预先连接小字符串,因为多个 stdout.writes 本质上是在进行连接,无论是屏幕缓冲区还是磁盘缓冲区。

为了进一步测试这一点,我将测试更改为编写 3 个块,每块 40 行。 REPL 时间保持不变。在 IDLE 中,它们的平均速度约为 0.058 和 0.05,与在 REPL 中一样快。

结论:我应该记录,如果一个人在 IDLE 中定期打印写入 运行 的代码并且关心速度,那么他应该先 assemble 预先 assemble 将他想要的所有内容一起显示到一个字符串中并打印该字符串。 IDLE 为回溯执行此操作,这就是它们显示 'all at once'.

的原因