按照作者的说法基本达到了和终端一致的速度。期待这个改进早日进入上游。
期待啊。
有相关的邮件列表讨论吗?
感觉 eglot
之类的包应该也是能够从这里获益的吧?
我觉得所有读外部进程输出的elisp代码都可以受益。原来的外部输出处理是全部在主线程里完成的,严重阻塞了外部进程的输出速度。现在这个改进把外部输出处理放到独立的线程里,可以允许外部进程全速运行,不被elisp的处理速度制约。
这个是很好的进步。
发去reddit推一推!
GitHub - tyler-dodge/emacs: Fork of emacs mirror Emacs. Has a background thread optimization for getting past the 1024 byte bottleneck on MacOS 的这个代码是在macOS中,emacs 28.0的代码。我照着他的代码在master分支上改了,可以编译运行。eshell中用top测试,能感觉出来光标闪烁比原版emacs稳定,速度更快,cpu更低。
但是可能是我patch的时候哪里有问题,emacs貌似有内存泄漏,跑一会top,内存就到300多MB,打开c的代码,color-rg grep几个关键字最高到900MB。
主要是28.0和29.0的 src/process.c
差异有点大。
我就是在reddit上看来的
可能代码还不成熟吧。但是
- 已经足够证明这是可以做到的
- 作者表示有意愿把它推进上游
这个patch看着主要是为提升eshell的使用体验。希望能早点推到上游。
不用等了,在同个话题里有个用户贴了他的修改patch(出处链接),macos上亲测有效(作者说他在linux上已经用了很久)。
修改:
modified src/sysdep.c
@@ -2533,6 +2533,15 @@ emacs_intr_read (int fd, void *buf, ptrdiff_t nbyte, bool interruptible)
}
while (result < 0 && errno == EINTR);
+ if (result > 0) {
+ for (;;) {
+ ssize_t r = read(fd, buf + result, nbyte - result);
+ if (r <= 0) break;
+ if (interruptible) maybe_quit ();
+ result += r;
+ }
+ }
+
return result;
}
外加init.el中
(setq read-process-output-max (* 1024 1024))
(setq process-adaptive-read-buffering nil)
这样修改以后真的已经快到我没啥可抱怨的了,eshell,shell,compilation-mode都快得跟终端窗口主观感觉差不多了。
原理大致是这样的:我们设置一个1Mb大小的进程输出缓冲区,Emacs去读进程输出,但是一次只读到了2k,然后就返回了。这时候外部进程还在继续输出,但是它最多只能再输出16k就得停下来,因为系统管道缓冲只有这么点。等Emacs处理完之前读到的2k,这次能回来能读到16k,读完以后外部进程又活过来,可以再最多输出16k.这样来回导致这1Mb大小的缓冲区完全用不上。
这个修改让Emacs每次一直读到read()返回0(外部进程已经没更多东西可输出了),或者缓冲区写满才停止。这让大缓冲区在外部进程高速输出时可以得到充分利用,而不至于堵在16k系统缓冲上。
为啥用了没感觉到有什么变化。。。终端下在emacs-mac源码里tree一下只需要0.1秒,修改后在emacs shell里tree一下还是要8秒多。
你说的对,这个C语言的修改没什么用,主要的变化是
(setq read-process-output-max (* 1024 1024))
(setq process-adaptive-read-buffering nil)
引起的,尤其是后者。
两个都设了,但还是没什么变化,也许是我编译姿势不正确。
我也试了tree一下emacs源码目录,加了(setq process-adaptive-read-buffering nil)是5.4秒,不加是21秒
我设成nil或t都是7~8秒左右,基本没变化…玄学
在我这里只加(setq process-adaptive-read-buffering nil)从21秒变成5秒。加不加 read-process-output-max 没有变化。
还是继续用Kitty吧…
这个patch合进上游了么,还是需要自己打?