有没有办法限制终端应用程序缓冲的文本量,以输出到显示器?
例如,如果我要调用一个尽可能快地将 2,000,000 行写入标准输出的应用程序,该应用程序可能会很快返回,但终端可能会在返回空闲提示之前再花几分钟显示闪烁的文本墙。大概这 2,000,000 行文本已被缓冲,并且终端应用程序正在通过缓冲区工作,生成数千个显示更新。有没有办法限制缓冲区大小,如果有超过例如 1,000 行要渲染,最旧的就被丢弃?
有没有办法限制终端应用程序缓冲的文本量,以输出到显示器?
例如,如果我要调用一个尽可能快地将 2,000,000 行写入标准输出的应用程序,该应用程序可能会很快返回,但终端可能会在返回空闲提示之前再花几分钟显示闪烁的文本墙。大概这 2,000,000 行文本已被缓冲,并且终端应用程序正在通过缓冲区工作,生成数千个显示更新。有没有办法限制缓冲区大小,如果有超过例如 1,000 行要渲染,最旧的就被丢弃?
这不是它的工作原理。
与管道类似,tty 行也具有相对较小的缓冲区大小。在我看来,终端行的内核缓冲区大小约为 12 kB。
(我怎么知道?我不想研究任何现有的源代码,也不想编写测试工具。所以我启动了一个终端模拟器,查询它正在使用的 tty 行(
tty
命令,假设它说/dev/pts/5
),然后冻结它通过发送 SIGSTOP。然后,从另一个终端,我使用非阻塞写入向其终端行发送了一些字节: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
,并 strace'd 终端仿真器从这个 fd 中寻找读取。)当应用程序将这么多数据发送到读取速度很慢的进程时,应用程序通常会阻塞它执行的写入操作。换句话说,读慢导致写也跑慢(更准确地说:有规律地进入“睡眠”状态,这样内核就可以运行其他进程,直到终端消耗了一些数据,进程可以写再次到 tty 线)。
自己看:开始一个
cat largefile
需要一分钟左右的时间。在另一个终端定位cat
的 PID(例如pidof cat
),假设它是 12345。然后查看哪个 fd 连接到cat
的输入文件:ls -l /proc/12345/fd
,找到属于 的行largefile
,很可能是 fd 编号 3。现在询问文件偏移量在哪个cat
位置,读取其输入文件:cat /proc/12345/fdinfo/3
. 您会注意到,当终端处理所有这些数据时,这个偏移量几乎呈线性增长;并且cat
只会在视觉终端活动停止之前退出一点点(这种差异甚至可能无法通过手动执行的命令来测量)。在我相当普通的笔记本电脑上,带有一个性能相当不错的终端仿真器(不是最好的,但也不错),处理 100 MB 的数据大约需要 10 秒。
几乎每个图形终端仿真器都尽可能快地处理输入,而不会一直更新显示(这将非常慢),有时(理想情况下每秒 60 次,调整为显示的刷新率)会短暂停止处理输入为了更新显示。一些终端模拟器保持这个刷新率,如果有连续的输入流要处理,一些终端模拟器会自适应地跳过帧。我的显示器每秒刷新大约 25 次,即在处理 100 MB 流期间大约刷新 250 次。
您要么拥有性能不佳的计算机或性能不佳的终端仿真器,要么夸大其词,或者您的数据更大。
终端没有这样的功能。
首先,他们需要一个更大的输入缓冲区,以确定他们是否可以进行这种跳过。大的输入缓冲区可能意味着在正常操作下不必要的显示更新延迟。
其次,您的回滚缓冲区将被破坏,您将无法回滚以查看先前的输出。
第三,即使是当前状态也可能被破坏,例如,如果它错过了改变颜色的转义序列或类似的东西。
不,这将是一个完全错误的特征。终端仿真器必须处理它们收到的所有数据。
那么,如果有一个正在运行的进程会打印出如此多的数据,以至于您必须等待几分钟,您该怎么办?
您可以使用 (SIGINT) 中断该过程
Ctrl+C
,或者如果这不起作用,您可以尝试通常更具侵略性的Ctrl+\
(SIGQUIT)。请记住,生产者应用程序几乎肯定仍在运行并且尚未打印这些数据——除非您将其中止。你可以切换到不同的终端模拟器选项卡或不同的应用程序,在那里做任何你想做的事情,然后再回到这个终端。
你可以稍作休息,伸展一下,凝视远处的某个点几秒钟,这很好。
您可以根据处理大量数据的速度来选择您喜欢的终端仿真器。
如果您的工作流程经常涉及将这么多数据发送到您的终端,那么重新设计您的工作流程。例如,将给定应用程序的输出通过管道
tail
传输,显然,它可以比终端仿真器更快地处理数据(它与该数据的关系要少得多)。向终端发送 100 MB 数据(200 万行)不应该成为您常规工作流程的一部分。你作为一个人将无法浏览它,更不用说正确处理它了,那有什么意义呢?发送到终端的 2M 线不是数据,是垃圾。它应该只是偶然发生并且很少发生,因此必须等待它,或者必须终止应用程序并以显着降低的详细程度重新启动它,不应该成为问题。
希望这可以帮助。