emacs 转 rust 的又一波冲击

有不少gpu加速的terminal,比如kitty、Alacritty、wezterm、warp等,感觉opengl绘制文字速度很快啊。

我们很多人混淆了执行性能和渲染性能。

执行性能的场景是用户不需要干预的情况下,就像rust比python快,gpu终端刷屏比2d矢量图快。

但是图形方面,绘制一个屏幕,特别是像emacs这样的文字绘制,gpu和cairo性能差距不明显,更多要关注多线程的技术不要卡住用户。

4 个赞

这些东西都很混,实际上的速度比不过 xterm,内存占用就更别说了。

而且字符一样是拿 FreeType 在 CPU 上绘制,最后上传至 GPU 进行绘制,Cairo 通过 X 服务器也是走的同一个流程。

2 个赞

emacs 的体验我感觉和语言上没有太大的关系,主要是架构设计上导致的一些弊端。希望是rust是因为想让emacs再能用个100年

想要再用 100 年,那只能依靠 C,流行语言迟早都会消失。

3 个赞

计算机编程史还不到100年,100年后该用自然语言和机器交流了

别的语言不好说,rust现在至少是能和linux kernel活一样长了 :rofl:

Linux 内核支持的平台一半以上都不支持 Rust,Linux 中的 Rust 代码也可以忽略,因为体积太小,而且都没必要开启。

1 个赞

为啥你会觉得一个标准都还没有的编程语言会长久?至少现在用 Rust 写的话大概率版本一更新就编译不了了。

6 个赞

其实和浏览器的情况是很类似的。出路就是Web Worker这样的完全独立的执行环境,Worker和宿主之间只能交换纯数据,不共享代码/对象,Worker也不能操作任何和用户界面有关的东西。

进程级别的异步操作已经有人做过了(use-package的作者) GitHub - jwiegley/emacs-async: Simple library for asynchronous processing in Emacs 。如果整合进核心的话,可以省去进程创建的开销,效率会更好一点。

1 个赞

刚看到前面已经有人提到这个问题了.

=============================

有个问题:

用户打断后, 有可能触发任何函数的执行, 有的函数可能会修改某些全局变量, 导致刚才保存的上下文失效, 比如一个heavy job执行到if条件判断语句, 刚刚判断完, 被用户打断了, 然后用户操作改变了某些变量, 导致刚才job里的if判断结果跟刚刚相反, 这样刚才的job恢复后, 有可能出现预料之外的结果. 就是说, 按照发生顺序, 用户操作之后不应该出现该行为的. 临界区问题.

这样的话, 还是需要锁的保护.

Cairo后端不也是opengl绘制么? 使用gpu做这种文字绘制不见得就会效率高,但是可以解放cpu,让系统更流畅。

不是,是CPU绘制

Cairo 用的是 XRender 扩展,在 X 服务器中进行加速。

另外,向图像处理器上传和下载数据的overhead经常大于绘制本身的overhead,因此 2D 图像最关键的是不要乱迁移数据,在 CPU 的数据保持在 CPU 内存中,在 GPU 上的数据尽量不要下载到 CPU 中。

我不认为这是个很大的问题, 因为可以设置为开发者允许的操作(比如用了 while-no-input 宏的代码)才是 yieldable, 然后里面用到的全局变量, 自行保存.

另外, 协程之间也可以有 channel mutex 这种同步机制. 无非就是获取锁失败之后把 coroutine 放回 scheduler 上等下一轮调度而已. 甚至可以直接用 coroutine 原语实现, 如

(defun try-lock-mutex (mtx)
  ;; 因为我们事实上是单线程程序, 因此无需 atomic
  (if (mutex-acquired-p mtx)
      nil
    (set-mutex-acquired-p mtx t)
    t))

(defun lock-mutex (mtx)
  (call1/cc
   (lambda (current-context)
     (while (not (try-lock-mutex mtx))
       (suspend-to-scheduler current-context LOW_PRIORITY)))))

这个要看 DDX,只要没用 xf86-video-fbdev 之类的驱动,一般都会有各种加速架构。

coroutine 也可以有同步机制, 比如两个 coroutine 抢一把锁, 抢不到的 coroutine 自己乖乖等下一轮 schedule. 这个锁可以基于 scheduler 和 coroutine 本身的机制实现. 或者用了 coroutine 的代码小心一点不要修改全局变量, 等到非 coroutine 代码里面再修改

你前面说的保存上下文跟操作系统内核里的保存线程上下文比较类似, 就是可以几乎任意位置保存(while-no-input也相当于内核中部分不可中断代码的处理), 而且以前的单核cpu也就相当于你说的"我们事实上是单线程程序", 场景基本一样, 所以, 理论上传统的多线程竞争和死锁问题应该是不可避免.

emacs的全局变量太多, 这个协程用到这几个, 那个协程用到另外几个, 也可能有交叉, 这样一把锁保护所有全局变量还是每个变量一把锁?

有栈协程和OS线程在保存现场类似, 只是一个是语言做了, 一个在OS做了。

但是多线程的关键就是不要多个线程访问一个资源, 特别是两个线程不能同时访问图形API。

所以,如果小心的写代码, 有栈协程可以一定程度缓解计算卡住, 只要可以随时中断就好了。 但是难的时, API调用链太长, 我们认为没有线程冲突的底部函数其实已经在相互冲突了。