this post was submitted on 17 Apr 2025
6 points (100.0% liked)

Emacs

472 readers
3 users here now

founded 2 years ago
MODERATORS
top 1 comments
sorted by: hot top controversial new old
[–] tal 2 points 5 days ago* (last edited 5 days ago)

From his other article linked from the submitted one:

https://batsov.com/articles/2025/04/07/emacs-startup-time-does-not-matter/

Emacs startup time doesn’t matter.1 Why so? Because of how people normally use Emacs, compared to some other editors:

If you’re the type of person who uses Emacs in the terminal, you’re likely using emacs --daemon

The basic idea that he's got is not new, which is that the solution to emacs having a long startup time compared to most terminal editors is to start it once in the background when a user session begins and then to never start it up more than once per user session. You should just connect to an existing lone instance using emacsclient.

Some software packages that one really wants to open quickly have this approach optionally available, like the virtual terminal program urxvt with urxvtd.

I fall into that "terminal user" camp that he thinks should be using emacs --daemon, but I can't agree on the "instance per user" thing. I use mostly instance per-project.

  • Some operations are blocking. If you do one of these in emacs while working on one thing, all of your other unrelated things for which you may be using emacs are also blocked. Yeah, there are ways around some of that and some mitigations. But for many things, the concept of something that blocks the whole instance is normal functionality. dired-do-shell-command, say. If you want per-instance stuff, then that needs to be gone and something closer to dired-do-shell-command-async needs to be the only option.

  • The minibuffer is instance-global. Leave an active minibuffer in one frame or terminal running emacsclient and you can't do anything elsewhere. It's hardly reasonable to ask me to not switch away from using the minibuffer on one task so that I can go play music in emms or edit a Threadiverse comment. You'd have to make the minibuffer operate at another level than instance.

  • Frankly, emacs doesn't make much use of multithreading internal to an instance, so one of the better ways to make use of parallel processing is to have concurrent instances. The rate of increase of serial computation no longer doubles every eighteen months, and has not since the early 2000s. Software's only route to getting more compute performance is parallelization. Yes, one single emacs instance is an easy way to avoid work on mitigating startup time. But using multiple instances is an easy way to get parallelization. Is it easier to fix startup time or parallelize emacs everywhere? I strongly suspect that the parallelization task is harder.

  • There is state that is per-instance all over that I want to be per-project. Take the buffer list. There is no standard convention for grouping buffer lists below this level. And yeah, I know that the article author is the dev of projectile, and projectile groups some things around projects, but not everything is a projectile project. dabbrev-completion candidates. next-error is per instance. If you want the instance of emacs to be a virtually-irrelevant technical detail merely used to optimize startup time, then everything instance-global like that needs to be purged from emacs. Everyone has to settle on one convention for "grouping" state like the above presently-instancewide things.

    I do run one fairly persistent emacs instance, which I use mostly to do email, since mu4e locks the mu database and isn't friendly to multiple concurrent emacs instances touching that. But there's just no way I'm switching to one emacs instance globally. I've tried it before, and the software isn't there yet.

If it became essential to use an emacs daemon to deal with startup time, I'd favor an approach more of the sort that I believe a few other, non-emacs packages have used. You start your "daemon emacs" instance. It completes startup. But after that, it does only a single task, never gets used for anything else. When someone spawns what would normally have been a new emacs instance, that "daemon instance" does a fork(). That's a fast operation. Might need to perform a few post-fork operations, but they shouldn't be substantial. Has to deal with shared system resources that cross fork(), like open file descriptors or shared memory or whatever. Needs to chdir() to where our emacsclient-like program was invoked. But that should be limited in the amount of work involved. Now you have a decoupled instance that doesn't have anything to do with the "daemon instance", but also doesn't need to do emacs startup until it's usable.

Emacs is highly portable, runs on many different platforms. Not all of them, especially the old ones, can fork(). It can run on MS-DOS, for example. But I'm okay having "fast startup" being some kind of optional non-core-functionality perk that is only available on some platforms, especially since I'm pretty sure that all modern platforms have fork().

Note that that doesn't permit for some other things that the "per user instance" model permits for that some users might want, like a shared global kill ring (though I could also see that as undesirable, stomping on state across projects, polluting kill-ring history). It doesn't reduce systemwide memory usage as much (I don't care much about that). But it does avoid a lot of problems that the "one instance per user" model brings with it.