emacs慢这锅不能是emacs自己背了

这个改善不了,现在只能把计算多的地方放到外部进程去,类似lsp-bridge这样比较现实。就是很多有洁癖的人不能接受

1 个赞

如果涉及linux上的机制,是会慢的。如果只是纯计算,我觉得差不多,今天测了下fib,wsl和win下是很接近的。业务线程也不是说必须单线程,前提是得能够合理的去拆分。unity这种引擎也支持多线程,但是本身的渲染线程/逻辑线程不允许别的线程直接介入。laya这种引擎是因为node本身就是逻辑单线程的,io部分由libuv接管(大概是这么个意思)。io那边可以开线程等待完成后,再同步逻辑线程。emacs本身其实也是这个意思,不开放多线程,我觉得没毛病。如果真的卡,也应该考虑将繁重的业务拆分到别的线程去。涉及到拆分业务的话,就需要插件编写者了解多线程的模型,这门槛就已经比较高了。理解的好,也不一定能处理的好,会引入风险。

简单来说,多线程能够带来的效果很明显。但是缺点也很明显,属于双刃剑。如果是正面,当然皆大欢喜。如果是负面,可能我们就接收不了了。

而如果不爽没有多线程,确实就可以像猫大那样用别的进程解决问题。但是我觉得这正是这个事情的最优解。既避免了提供多线程可能导致emacs崩溃的问题,也让有能力自己开进程解决问题的人有活路走。也就是说,自然会有更专业的人出来解决这个问题。

老实说我觉得公司的windows下比我自己的linux下流畅的。但是不习惯windows下的开发环境,所以还是自己带了一块rock pi 5b当单板服务器用。目前让我最难受的是开X forward的情况下因为网络不稳定导致的卡顿。

至于多线程什么的,elisp有多线程支持,只是缺乏必要的调试手段,测试困难。Emacs里面用的更多的是多进程IO。本来在linux下面就不分进程和线程的。

emacs那是协程的实现,不是并发线程。

emacs之所以多线程不好是大多数emacser根本就没写过图形多线程,然后不懂图形编程,分不清楚协程和并发线程,还喜欢抬杠好为人师哇,悲哀啊。

有空可以好好读一下我写的原因吧,New Emacs 构想 - #66,来自 manateelazycat

1 个赞

可能我说的让他们误解了, emacs的的其他线程应该是没大面积接触到emacs逻辑层面的处理的。定时器那些异步的东西其实也是在主线程里面跑的。是lua/c++现在的那种无栈协程吧,只是将当前线程的资源尽可能的利用不让它空闲而已,实际上真正做事的还是那个线程。

单纯吐槽一下言辞,没有说你这部分说的有问题,不过你说的 Emacs 29 之后慢是插件作者的锅这点就有点不敢苟同了,比较怀疑楼主是否有真正写过 Emacs 的插件:

  1. Emacs 本身就是提倡单线程的,不存在暴露多线程给插件开发者的情况,因为内置的基本函数压根就不标明其是否是线程安全,尽管提供了 thread 库,先不论其是否是真正的多线程, thread 库出来这么久了,插件用到它的地方也基本只在 I/O 上。

  2. 不说插件, Emacs 内置的代码都有很多是这样的:

    (unwind-protect
        (progn
          ;; 改变某个全局状态
          ;; ...
          )
      ;; 恢复某个全局状态
      )
    

    虽然看上去比较 Tricky ,但在单线程的 Emacs 下都是可靠的代码。

  3. Emacs 的标准文本处理逻辑,可以说都是在 save-excursion 中用一系列命令在缓冲区内移动 point , 执行对应进行编辑或查询,这虽然很优雅,但是本来就不快,因为各种琐碎的光标移动命令之间无法复用中间结果,永远不知道一条简单的光标移动命令的背后包含着多少次的正则表达式匹配。

1 个赞

本质是emacs插件包袱是不可能抛弃掉的,抛弃不掉,你再这么革新多线程,没有插件也没用。

要支持现有插件,多线程根本没法支持,elisp那么多状态,那么多hook,那么多macro,没法多线程管理。

唯一的方法就是往外部进程卸载计算。

其实你第一楼是不严谨的,emacs大多数卡是post command太多或者大数据导致的gc回收不及。

本质是没有多线程的原因。

但是你很多表述不严谨,异步进程只要返回大量数据让emacs处理就会卡,lsp-mode本质就是异步调用lsp server,为什么卡呢?lsp server本身不会卡emacs,但是它吐很多数据硬塞给emacs处理,emacs处理不过来就卡,产生过多gc就会导致卡顿加剧。

gc不是不会卡,而是你产生的数据量不够大,你对几千条字符串做一个复杂正则和overlay操作,马上就卡了。

我觉得不能脱离emacs生态谈技术,那个谁都会,但是怎么改善emacs呢?

你有很好的学习劲头,可佳可赞,但是思考不严谨。

彻底解决emacs卡的方法是,把emacs当做elisp解释器用,界面绘制和界面状态管理用新的进程去弄,这样启动多少个elisp解释器都没问题。

这样既可以利用现代界面和并发多线程,又可以兼容elisp语法写阻塞插件慢慢算。

这就是neovim的做法,可行有效果,什么时候有希望呢,哪天哪个牛人花几年时间写一个新的emacs前端,只要效果好,大家都愿意转。

其实我觉得clojure+ skia是最少纠结的实现方法。

抛砖引玉。

1 个赞

我没怪插件的作者。我的意思是如果遇到emcas卡,多找找插件是不是把io/异步这些东西处理好了,解决方法是不是可以优化,别总是怪emacs gc不ok,没多线程。

unwind-protect是一个异常处理上的问题,有可能是想这段代码不管出不出问题后续的代码都应该继续执行,且必须清除之前对全局变量的操作。如果只是关注全局变量操作恢复,用let临时绑定也行,但是考虑到要进行异常处理,我不觉得这个地方有什么不妥。

你说的正则匹配什么的,29之前可能是问题。29之后好好写,应该不会造成问题,本质就是一些计算。如果并不涉及io阻塞,除非里面写出了恶性的循环,或者需要对一个大文件进行一次扫描这种耗时操作,理论上不会卡。如果里面做了大量耗时操作,是不是应该考虑优化呢。 如何实现同样的操作,得看是在什么样的场景下。你说的这个情况就像是,我要用反射,就有些人喜欢跳出来说反射慢。但是不问我要在什么地方什么场景下面用,实际上我用反射的地方可能服务器启动10天只会调用到10次,这东西能不能用你得先预估或者算一下。1个编辑操作1ms完成和2ms完成对用户来说并没有什么不同。如果一个操作花了一秒,就算语言本身性能提升5倍,也是200ms的延迟,这个用户就可以感知得到了。用户不觉得卡,你怎么实现顶多是优雅不优雅的问题。

今天我做了一次fib的bench, emacs开native-comp (speed 2) 大概比jit过后的python,lua慢2-5倍。但是要好过没jit的python。本身数据处理量不大的话,你用哪个语言感知是不强的。按我的理解,29之后,emacs已经提供足够好的性能了。

这种情况我建议只对视窗下的界面做渲染,数据量太大go这种也gc不过来的。当然同样没优化的情况下,go 肯定比emacs挺的更久,抗住的数据量更大。

如果是大数据量可以考虑用对象池,只对可视范围做渲染这样的方式做优化。优化的方式还是有的,就是愿不愿意去做的问题。语言本身如果性能更好,当然皆大欢喜。当然,emacser都是用爱发电,我也不能要求他们都按照商业项目的标准去优化。

谢谢,我想到一个问题,既然都是多线程,在事务原子性前提下,理论上二者应该没有区别吧?

协程实现的多线程代码如果多处理执行会产生新的问题吗?

要看是有栈还是无栈,像go这种有栈携程可以拿到线程,是可以真正并行的。lua那种无栈的,不会跑到别的线程上执行,不能说是并行的。

建议搜索一下,肯定是有区别的

blink-search已经是针对界面做渲染处理的,效果是很好,但是我要说的是,仅限于普通的列表渲染实现复杂度还行。

但是对于上下文很长的情况,像emacs这种编辑器,还有很多视窗外的对象需要处理,编辑器级别做可视化坐标渲染转化工作量会大很多。

我之所以回复这么多就是如果你有什么想法你自己做吧,现在的问题不是能不能做的问题。而是做之前你和不懂的人沟通,浪费彼此的时间。

因为你和没有做过图形编程的人沟通,你并不会说服他们,他们反而拿着局部的知识和你掰扯对和错,你要从普及多线程图形编程开始说,累不累啊?

2 个赞

话说现在mps有望解决gc导致卡顿的问题吧

没用过哇, 期待。

有编译好的mps版本,猫哥品鉴下呢