有没有办法限制终端应用程序缓冲并输出到显示器的文本量?
例如,如果我要调用一个尽可能快地将 2,000,000 行写入 stdout 的应用程序,该应用程序可能会快速返回,但终端可能会再花几分钟显示闪烁的文本墙,然后返回空闲提示。据推测,这 2,000,000 行文本已被缓冲,并且终端应用程序正在通过缓冲区工作,生成数千个显示更新。有没有办法限制缓冲区大小,例如,如果有超过 1,000 行尚未渲染,则最旧的行将被删除?
答案1
如果我要调用一个尽可能快地将 2,000,000 行写入 stdout 的应用程序,该应用程序可能会快速返回
事情不是这样的。
与管道类似,tty 线路也具有相对较小的缓冲区大小。在我看来,内核的终端线缓冲区大小约为 12 kB。
(我怎么知道它?我不想研究任何现有的源代码,也不想编写测试工具。所以我启动了一个终端仿真器,查询它正在使用的 tty 行(tty
命令,让我们说它说/dev/pts/5
),然后冻结了然后,从另一个终端,我使用非阻塞写入将一些字节发送到其终端线:dd if=/dev/zero of=/dev/pts/5 bs=65536 oflag=nonblock
。)
可能有多个缓冲区相互连接,例如,如果您正在运行tmux
或类似情况,那么数据将通过两条 tty 线路以及 tmux 的内部缓冲进行遍历,或者如果您正在运行ssh
ssh 服务器、网络和 ssh 客户端还添加一些缓冲区,但您拥有的总体缓冲区大小仍然比您正在处理的数据量低很多(大约 100 MB,假设平均每行 50 字节)。
终端仿真器也以类似的小块读取输入,例如大约 4 - 8 kB。
(我怎么知道?我检查了/proc/<terminal's pid>/fd
哪个文件描述符对应于终端线的主端/dev/ptmx
,并跟踪终端仿真器以查找从此文件描述符中读取的内容。)
当应用程序将这么多数据发送到读取速度缓慢的进程时,应用程序通常会阻塞其执行的写入操作。换句话说,缓慢的读取器会导致写入器也运行缓慢(更准确地说:定期进入“睡眠”状态,以便内核可以运行其他进程,直到终端消耗掉一些数据并且该进程可以写入再次到 tty 线)。
要亲自查看:启动一个cat largefile
需要一分钟左右的时间。在另一个终端中找到cat
的 PID(例如pidof cat
),假设它是 12345。然后查看哪个 fd 连接到 的cat
输入文件:ls -l /proc/12345/fd
,找到属于 的行largefile
,很可能是 fd 编号 3。现在询问文件偏移量at 其中cat
正在读取其输入文件:cat /proc/12345/fdinfo/3
。您会注意到,当终端处理所有这些数据时,该偏移量几乎呈线性增长;并且cat
只会比视觉终端活动停止早一点退出(这种差异甚至可能无法通过手动执行的命令来测量)。
再过几分钟
在我相当普通的笔记本电脑上,终端仿真器的性能还不错(不是最好的,但也不错),处理 100 MB 的数据大约需要 10 秒。
数千个显示更新
几乎每个图形终端模拟器都会尽可能快地处理输入,而无需一直更新显示(这会慢得难以忍受),有时(理想情况下每秒 60 次,根据显示器的刷新率进行调整)会短暂停止处理输入以更新显示。有些终端模拟器会保持此刷新率,有些终端模拟器会在有连续输入流需要处理时自适应地跳帧。我的显示器每秒刷新显示次数约为 25 次,即在处理 100 MB 流时刷新显示次数约为 250 次。
你要么有一台性能不佳的计算机,要么有一个性能不佳的终端仿真器,要么夸大了,或者你的数据更大。
有没有办法限制缓冲区大小,例如,如果有超过 1,000 行尚未渲染,则最旧的行将被删除?
终端没有这样的功能。
首先,他们需要更大的输入缓冲区,以确定他们是否可以进行此类跳过。正常操作下,大的输入缓冲区可能意味着不必要的显示更新延迟。
其次,您的回滚缓冲区将被破坏,您将无法回滚以查看以前的输出。
第三,即使当前状态也可能被破坏,例如,如果它错过了改变颜色或类似内容的转义序列。
不,这将是一个完全错误的特征。终端仿真器必须处理它们接收到的所有数据。
那么,如果正在运行的进程打印大量数据而您必须等待几分钟,您该怎么办?
您可以使用Ctrl+C
(SIGINT) 中断该过程,或者如果这不起作用,您可以尝试通常更激进的Ctrl+\
(SIGQUIT)。请记住,生产者应用程序几乎肯定仍在运行,并且尚未打印这些数据 - 除非您中止它。
您可以切换到不同的终端模拟器选项卡或不同的应用程序,在那里执行您想做的任何操作,然后再返回到此终端。
你可以短暂休息一下,伸展一下身体,凝视远处的某个地方几秒钟,效果很好。
您可以根据终端模拟器处理大量数据的速度来选择您喜欢的终端模拟器。
如果您的工作流程经常涉及将这么多数据发送到您的终端,那么请重新设计您的工作流程。例如,通过管道传输给定应用程序的输出tail
,显然,它可以比终端模拟器更快地处理数据(它与该数据有关的事情要少得多)。
向终端发送 100 MB 数据(200 万行)不应该成为您常规工作流程的一部分。你作为一个人无法浏览它,更不用说正确处理它了,那还有什么意义呢?发送到终端的2M线路不是数据,而是垃圾。它应该只是偶然发生并且很少发生,因此必须等待它,或者必须终止应用程序并以明显较低的详细程度重新启动它,不应该成为问题。
希望这可以帮助。