[HN Gopher] A vision of a multi-threaded Emacs
       ___________________________________________________________________
        
       A vision of a multi-threaded Emacs
        
       Author : pxc
       Score  : 118 points
       Date   : 2022-05-30 15:07 UTC (7 hours ago)
        
 (HTM) web link (coredumped.dev)
 (TXT) w3m dump (coredumped.dev)
        
       | CJefferson wrote:
       | Note: Not at all an emacs expert, but know some stuff about
       | trying to parallelise a long-standing language ( GAP -- www.gap-
       | system.org , 30 year old maths language).
       | 
       | I'd strongly recommend something like Javascript's "web workers",
       | where each thread lives in an almost entirely independent memory
       | space, with sharing limited to explicitly named buffers.
       | 
       | The problem with traditional "everything shared by default"
       | threading is even when you get the basic core working, we found
       | throughout the system there were buffers and caches, which all
       | needed making thread-safe. Even after that, every library needed
       | some fixes -- and while these were often simple these libraries
       | may not have had updates in years.
        
         | taeric wrote:
         | I'd argue that emacs already has that with process buffers
         | using sentinels. :D
         | 
         | By and large, if you don't write blocking code, it doesn't
         | block. Big caveat here is the TRAMP logic to establish
         | connections can block. Not sure why those weren't done in a
         | more async way.
        
           | joseph8th wrote:
           | This is my only real gripe, as well. I really like Tramp, so
           | I use it anyway, but I gripe about it when it hangs
        
         | admax88qqq wrote:
         | WebWorkers are not very useful as a result. The communication
         | overhead of copying data between two memory spaces usually
         | dwafs any apeedups you could get from doing the work in
         | parallel.
         | 
         | It's easier to implement as a language and runtime, but to get
         | truly high performance on today's many thread many core
         | machines you need shar d memory concurrency more like Java
        
           | CJefferson wrote:
           | True, they are of limited usefulness, but in Emacs you could
           | (probably) make them more useful over time by exposing more
           | and more sharing -- but (I'm again guessing, don't know
           | Emac's insides) it might be easier/safer to start sharing
           | nothing, then work on sharing as much as possible, rather
           | than start with full sharing and then try to make everything
           | work.
        
           | jlokier wrote:
           | _> to get truly high performance on today 's many thread many
           | core machines you need shared memory concurrency more like
           | Java_
           | 
           | JavaScript supports shared memory concurrency.
           | 
           | Shared memory1 is available in browser WebWorkers these
           | days.2
           | 
           | Atomic ops for building multi-threaded data structures3 are
           | available too4.
           | 
           | Including primitives for thread synchronisation56 used by
           | mutexes, condvars, producer-consumer queues, etc.
           | 
           | 1 https://developer.mozilla.org/en-
           | US/docs/Web/JavaScript/Refe...
           | 
           | 2 https://caniuse.com/sharedarraybuffer
           | 
           | 3 https://developer.mozilla.org/en-
           | US/docs/Web/JavaScript/Refe...
           | 
           | 4 https://caniuse.com/mdn-javascript_builtins_atomics
           | 
           | 5 https://developer.mozilla.org/en-
           | US/docs/Web/JavaScript/Refe...
           | 
           | 6 https://caniuse.com/mdn-javascript_builtins_atomics_wait
        
         | KerrAvon wrote:
         | The author discusses essentially this option in "A jumping off
         | point."
        
         | convolvatron wrote:
         | one really nasty conflating issue is that emacs uses a mess of
         | globals. partially because of the domain but largely because of
         | dynamic binding and the lack of namespaces.
         | 
         | emacs really needs to be hoisted onto another language and
         | runtime. everyone says this but no one can really conceive of
         | doing this and rewriting or at least refactoring all the elisp
         | extensions.
         | 
         | I guess guile emacs is still alive? I should really try
         | installing it
        
           | rurban wrote:
           | guile-emacs has atrocious string performance
        
         | funcDropShadow wrote:
         | In principle I agree whole heartedly. When introducing
         | parallelism and or concurrency into an old language, the "web
         | workers" aproach, or Erlangs actors, to name a decades older
         | reference to a similar idea, should always be considered. The
         | problem with emacs in particular is the use of the buffer as
         | the most versatile data structure. Lot's of data that could
         | live in some data structure lives in some overlay over some
         | part of the buffer. And emacs is built on dynamic variables.
         | Others in this thread have argued to "just refactor" them to
         | lexically scoped variables. But that would decimate the largest
         | vector to adapt and modify the system.
         | 
         | Parallelizing Emacs needs to be a long-term endaveour, as the
         | maintainers of Emacs already said years ago. I think Emacs
         | could learn something from Clojure's story for parallelism.
         | Make data structures immutable by default, and reference them
         | from as few global variables as possible. The "make data
         | structures immutable by default" ship has already sailed, but
         | introducing additional immutable list/vector/map/set data
         | structures with first class syntax support would allow newly
         | written code to prepare for a more parallel future. Such
         | immutable data structures could then be shared between
         | different "ELisp web workers". The "as few global variables
         | story" ship has already sailed, but again ELisp authors would
         | start to consider reducing the number of global variables if it
         | would enable multi-threading.
        
         | brabel wrote:
         | Yeah, I think that's the way... Dart does this well with
         | Isolates[1]. The language is basically single-threaded but you
         | can start Isolates that run on different Threads but have their
         | own independent memory, and they can exchange messages, much
         | like in the Actor model. Not having to worry about real shared
         | memory between Threads as in C++ or Java is incredibly
         | liberating. As others point out, however, for extremely high
         | performance that's not the best solution, but for nearly all
         | applications, including emacs, the Isolate approach is plenty
         | good enough.
         | 
         | [1] https://dart.dev/guides/language/concurrency
        
       | Kaze404 wrote:
       | I'd love to see this someday, as an Emacs user. One of my biggest
       | frustrations with Emacs is how it can simply just hang while
       | waiting for anything IO bound (like a response from LSP). It
       | mostly only happens when opening a new file, while in VSCode for
       | example the file is opened immediately and things like LSP and
       | syntax highlighting are loaded in the background.
        
         | SoftTalker wrote:
         | I use Emacs all day, every day at work for the last 20 years.
         | I'd like to see these changes too, but honestly it's not even
         | close to being on my top 10 of frequent frustrations. The
         | average web app is way less responsive, suffers random hangs,
         | HTTP 500 errors, browser freezes, etc. than I experience in
         | Emacs.
        
         | TacticalCoder wrote:
         | > ... while in VSCode for example the file is opened
         | immediately and things like LSP and syntax highlighting are
         | loaded in the background.
         | 
         | I'm not saying you're not experiencing what you're describing
         | but I find that weird because I use Emacs with LSP and the
         | system is responsive while LSP loads up. And I'm using lsp-
         | mode, not Eglot (I should really try Eglot). I mostly use it
         | for Clojure: I'm using both Cider and lsp-mode and they work
         | fine together. And as soon as I open any Clojure source file, I
         | can keep using Emacs while LSP starts (which is not that slow
         | btw: only about three seconds I'd say). LSP is one of those
         | things that runs in another process, so it's one of those case,
         | for me at least, where Emacs acts like if it was multithreaded.
         | I haven't seen this lock up / freeze while waiting for some LSP
         | server answer.
         | 
         | For example I'll typically open a Cojure file, lsp-mode shall
         | begin loading automatically and then I manually launch Cider:
         | everything happens "simultaneously" and I'm not blocked.
         | 
         | I'll play more attention with other LSP servers (like the CSS
         | one) but nothing strikes me as slow or frozen.
         | 
         | If there's one thing I could complain about is that when I'm
         | busy doing other things (because my Emacs ain't blocked), I see
         | spurious LSP messages telling me where it's at kinda
         | distracting me.
         | 
         | Now I take you're using a native-comp Emacs? And a fast JSON
         | parsing lib?
         | 
         | Emacs 28, native comp, lsp-mode, AMD 3700X, NVMe SSD, 16 GB of
         | RAM. A good machine but nothing crazy fast.
        
           | taeric wrote:
           | I have seen some folks that don't realize they are bypassing
           | the native-json parser by having debug logging turned on. So,
           | could be that?
        
         | NeutralForest wrote:
         | My biggest pet-peeve is Org freezing when I'm exporting to PDF.
        
           | OrderlyTiamat wrote:
           | I've had that fixed in the past by simply adding an ampersand
           | to org's compile command. This does make it run in the
           | background but makes it ring the bell a number of times. Now
           | when I'm editing and want to see the compiled pdf side by
           | side I just start a bash while loop that recompiles
           | continually with latexmk.
        
         | d0mine wrote:
         | You don't need multiple threads to perform IO asynchronously.
         | 
         | And in reverse, using threads won't prevent lock-ups: the
         | opposite is likely. [Pre-emptive] threads compared to external
         | processes require much more careful coordination that is hard
         | to achieve if you are installing dozen of emacs packages
         | written by different people that manipulate the same state.
         | 
         | unrelated, it is one of the arguments in favor of GIL such as
         | in CPython--it is easier to get right than fine-grained locks.
        
           | KMag wrote:
           | Agreed. Raw threads are almost always the wrong application-
           | level concurrency abstraction. Actors/Erlang-style
           | concurrency and futures are both much better abstractions for
           | application programmers. I'm also a big fan of threads with
           | compile-time proofs against data races, a la Rust, but I can
           | appreciate it's a lot to learn for many application
           | programmers.
        
         | metroholografix wrote:
         | That multi-threading will solve this issue, is a common
         | misconception. Emacs already supports asynchronous I/O and has
         | sentinels for exactly that. However, not everything that runs
         | on Emacs is taking advantage of that functionality. It is
         | therefore up to you, to use the proper package (or not use the
         | wrong one) / configure Emacs in such a way, so that this sort
         | of issue is avoided. I can definitely say that if you're
         | experiencing I/O hangs, it's either misconfiguration or bad
         | code in a package that you loaded.
         | 
         | Finally for LSP, I always recommend Eglot over LSP Mode, as
         | Eglot is written by an Emacs contributor that has deep
         | knowledge of Emacs and Emacs Lisp. LSP Mode is written by
         | volunteers on Github, and the code is nowhere near as good.
         | 
         | Given the (enormous amount / ever-increasing number) of Emacs
         | Lisp packages out there, a lot of them being substandard, being
         | able to make these sort of qualitative calls (and also
         | increasingly dive into Emacs internals) will pay off. Assuming
         | moderate effort, this will come with experience and time spent
         | using Emacs.
        
           | mdkdkdk wrote:
           | I've seen you post this criticism before, but the line
           | "volunteers on GitHub" is pure FUD. Is the Eglot guy paid for
           | writing Eglot, or he hosts somewhere else, so it's better?
           | 
           | "The code is nowhere near as good" according to you? Give a
           | concrete example of where the LSP code has real deficiencies;
           | Eglot isn't as fully featured, is more opinionated, and its
           | stans are more annoying.
           | 
           | Sounds to me like the LSP project is helping new hackers
           | learn Emacs, and Eglot is one bus accident from being
           | unmaintained, frankly.
        
           | Kaze404 wrote:
           | Wow, I had no idea! I'll give Eglot a try, thank you :)
        
           | rprospero wrote:
           | While I appreciate the comments on Eglot vs LSP, the number
           | one package that hangs my system is Gnus. It's still my
           | favourite e-mail client, but I'm cut off from coding for
           | twenty seconds every time I check my e-mail.
           | 
           | Are we really ready to declare that Lars Magne Ingebrigtsen
           | is a substandard Emacs Lisp coder?
        
             | michaelmrose wrote:
             | I use mu4e so I don't know if the workflow converts but I
             | watch for new email outside of Emacs entirely and upon new
             | email run offlineimap and after sync have it run
             | mu4e-update-index via emacsclient.
             | 
             | This means Emacs always has an up to date view of my email
             | within a ~30 second window of the email being received and
             | all I'm asking it to do is query mu which takes ms.
        
             | alex_smart wrote:
             | Gnus has been around since the mid 90s (and predates the
             | addition of asynchronous url-retrieve api to emacs). It is
             | unfair to compare it with packages that written in the last
             | couple of years.
             | 
             | I don't use Gnus so I have never bothered looking at its
             | internals, but if it is locking your emacs for twenty
             | seconds checking email, it is probably not doing much
             | asynchronously. It is notoriously hard to convert existing
             | synchronous code to asynchronous without using threads.
             | Promises/futures/continuations/whatever-you-want-to-call-
             | them are a pretty all in affair. Not having the time
             | investment that would take to convert a 100k line codebase
             | to async does not make Lars Magne Ingebrigtsen a
             | substandard Emacs Lisp coder.
        
               | metroholografix wrote:
               | This. Gnus is a behemoth, has been around for decades and
               | is also the result of many contributions from many
               | different people. It will take time for it to evolve
               | (it's slowly happening).
               | 
               | Lars is amazing by the way, his relentless Emacs work and
               | prolific bug killing in the last few years should be
               | praised to high heavens.
        
               | kwhitefoot wrote:
               | Not only that but he is incredibly responsive to random
               | people (including me in the past) reporting bugs in Gnus.
               | Years ago I reported something on a Friday morning and he
               | replied directly to me with a workaround by the
               | afternoon.
        
           | Athas wrote:
           | Joining the eglot choir. It behaves like I expect Emacs modes
           | to behave and hooks into other Emacs functionality (xref,
           | eldoc). Actually, it behaves better than that: it often works
           | with zero configuration, which is much better than I expect.
        
           | chrsig wrote:
           | This is putting a lot of blame on the user, who likely has no
           | clue how emacs i/o behaves.
           | 
           | > if you're experiencing I/O hangs, it's either
           | misconfiguration or bad code in a package that you loaded
           | 
           | I mean...yes. That's the issue. The issue is that it's
           | possible to have i/o hangs caused by misconfiguration or
           | elisp packages.
           | 
           | The solution isn't to tell the user to do something
           | different, it's to make it so that elisp execution can't
           | cause i/o hangs.
           | 
           | edit: to a be a bit more precise with language: "i/o hang"
           | should be interpreted as "making the UI unresponsive or
           | preventing other tasks from completing".
        
             | medstrom wrote:
             | How would you make it impossible to make the UI
             | unresponsive? Given that lots of packages directly want to
             | do stuff with UI?
        
               | chrsig wrote:
               | I'm not going to have a great answer for how, especially
               | in something with as much legacy as emacs. And I
               | certainly don't mean to imply that solving the problem is
               | easy (or possible for 100% of cases), or otherwise
               | detract from efforts that the community has made.
               | 
               | My intent was to highlight on what a good solution looks
               | like from a user perspective.
               | 
               | Off the top of my head, in an incredibly hand-wavey
               | fashion:
               | 
               | A quick win would be to set a timeout on every single i/o
               | action, with the default timeout being quite low. That
               | doesn't remove the problem, but it'd probably be a good
               | start towards easing the user pain. Bringing an
               | indefinitely long hang down to 1s is a win.
               | 
               | For a total solution, I'd consider looking into
               | implementing a concurrency model with a preemptive
               | scheduler, probably using erlang as inspiration. have
               | updates to the ui becoming a message sent to the ui
               | inbox, and the routine for rendering the ui just reading
               | from the inbox and applying the given command.
               | 
               | This is without thought to how to actually implement
               | that, and what implications it would have on legacy
               | elisp, or how legacy elisp could be brought into a CSP
               | world without breakage.
               | 
               | So just some armchair architecting on a day off for a
               | project I've never worked on :)
        
             | jrockway wrote:
             | > This is putting a lot of blame on the user
             | 
             | I think you're missing the point. Emacs already contains
             | all the support necessary to make LSP not lock up the UI,
             | LSP simply doesn't use it. So if you say "LSP is a great
             | use case for multi-threaded Emacs", that's not correct.
             | 
             | The problem with LSP specifically is that Emacs doesn't
             | really know what the language server is going to do, and if
             | it let you update the text while the language server was
             | also updating the text, it would have to have some way to
             | merge the changes that you made while the language server
             | was busy. There would need to be some spec for that, or
             | more likely, another trip to the language server to figure
             | out what to do. You could, of course, edit the text while
             | that second trip was happening, and this algorithm never
             | converges to a finished state. So, it locks the UI so you
             | can't make any edits until the text from the language
             | server comes back. That's the easy way out, but at least it
             | results in an algorithm that terminates.
             | 
             | The way to fix this is to figure out where the time is
             | being spent. If it's on JSON marshaling/unmarshaling, speed
             | that up. If it's because the language server is slow, speed
             | that up. The only compromise right now would be to let you
             | edit buffers in a different project while the language
             | server is processing something. I don't think anyone wants
             | to do that; "I don't want LSP to lock up Emacs" really
             | means "I want my language server to perform all operations
             | instantly." So get out that profiler for your language
             | server, I think.
        
               | bitwize wrote:
               | > I think you're missing the point.
               | 
               | I don't. "The only thing that matters in software is the
               | experience of the user." The Emacs user experience is
               | full of I/O hangs; the VSCode experience is not. This is
               | a problem that needs to be solved if Emacs is ever to
               | have a significant installed base again.
        
           | light_hue_1 wrote:
           | > I can definitely say that if you're experiencing I/O hangs,
           | it's either misconfiguration or bad code in a package that
           | you loaded.
           | 
           | As an emacs user and package developer of 20 years I can
           | definitely say you are totally wrong. This is the kind of
           | dismissive, unhelpful, and frankly extremely discouraging
           | attitude that is slowly killing emacs.
           | 
           | Instead of taking responsibility for the fact that emacs is
           | incredibly slow because of poor architectural decisions (like
           | an insistence to not using fast native libraries and an
           | incredibly slow language), the solution is apparently to
           | blame the people who create packages. If developers they are
           | creating packages that are slow, it is not their fault. It is
           | the fault of emacs developers in refusing to modernize the
           | architecture in a way that enables people to make efficient
           | code.
        
             | metroholografix wrote:
             | > This is the kind of dismissive, unhelpful, and frankly
             | extremely discouraging attitude that is slowly killing
             | emacs.
             | 
             | Emacs seems to be doing just fine if not thriving.
             | 
             | > Instead of taking responsibility for the fact that emacs
             | is incredibly slow because of poor architectural decisions
             | (like an insistence to not using fast native libraries and
             | an incredibly slow language)
             | 
             | For me, Emacs is both incredibly fast and incredibly
             | stable. For an "Emacs user and package developer of 20
             | years", you seem either too quick to jump to conclusions or
             | are still barely scratching the surface of what's possible
             | which makes me question the depth of your expertise and/or
             | how efficiently your time with Emacs was invested.
        
             | natrys wrote:
             | The presupposition that anything is killing Emacs - much
             | less this - requires concrete proof. Because if anything,
             | in my (likewise subjective) experience it's the complete
             | opposite. I see more forum activity from newcomers and more
             | high quality packages emerging each year than ever before.
             | 
             | > like an insistence to not using fast native libraries
             | 
             | How? Even disregarding graphics and font stack which almost
             | entirely leverages native libraries, my Emacs build links
             | against gmp, libpng, librsvg, zlib, alsa-lib, libxml2 and
             | so on. 27.1 introduced jansson for native json parsing over
             | pure elisp, from 28.1 we can basically AoT compile elisp to
             | native code using libgccjit, master branch (29) even
             | bundles sqlite these days. That is not to mention module
             | system had been stable for a while, and lot of packages
             | already use this to offload computation heavy stuff to
             | native code.
        
             | alex_smart wrote:
             | If your lsp-client code is doing anything where you need
             | binding with a native library or the speed of emacs lisp is
             | a factor, you _are_ doing it wrong. All an lsp-client needs
             | to do is make requests to the lsp-server, listen to the
             | responses and update the UI. It literally doesn 't matter
             | how slow emacs-lisp is.
             | 
             | The only way an lsp-client could be slow is by making a
             | request to the server and then blocking on the response -
             | which is wrong and the package writer's fault because they
             | are not using the asynchronous api emacs provides for
             | communicating with a process.
        
               | gcommer wrote:
               | There's tons of little details and inefficiencies in
               | elisp that crop up such that easy things like "listen to
               | responses" are hard to get fast. Random example: before
               | native json support, large lsp responses (which can be
               | multiple megabytes from some servers!) would take over a
               | second and hitch the UI just to parse the json response.
               | And that was after a lot of work to get response parsing
               | dominated by json instead of GC time.
        
             | jhgb wrote:
             | > and an incredibly slow language
             | 
             | Languages are not slow or fast; their implementations are.
             | There's absolutely nothing wrong with Emacs being
             | programmed in Lisp and it sure as hell isn't "a poor
             | architectural decision". If Emacs is slow because of its
             | implementation of Emacs Lisp, it's time to fix its
             | implementation of Emacs Lisp.
        
               | light_hue_1 wrote:
               | > There's absolutely nothing wrong with Emacs being
               | programmed in Lisp and it sure as hell isn't "a poor
               | architectural decision"
               | 
               | I love Scheme and Lisp. I've probably written several
               | million lines of code in both Scheme and Lisp and I've
               | contributed code to several Lisp and Scheme compilers.
               | 
               | But languages are absolutely slow or fast! There are fast
               | Schemes and Lisps and there are slow ones. Emacs has
               | probably the slowest one by far. For example, Emacs still
               | relies on dynamic binding after all of this time. That's
               | a performance disaster.
               | 
               | There is simply no efficient implementation of Elisp
               | possible as it stands and as it is used today. Even with
               | JIT compiling Elisp performance is simply wretched.
        
               | jhgb wrote:
               | > I've probably written several million lines of code in
               | both Scheme and Lisp
               | 
               | BTW you _do_ realize that this would put you at
               | (sustained, average) several hundred lines of code per
               | day ( _every_ day) over your lifetime? That sounds almost
               | depressingly bleak to me. How does one have a life
               | outside of that?
        
               | light_hue_1 wrote:
               | > BTW you do realize that this would put you at
               | (sustained, average) several hundred lines of code per
               | day (every day) over your lifetime? That sounds almost
               | depressingly bleak to me. How does one have a life
               | outside of that?
               | 
               | Grad school sure puts you on the right track of getting
               | good numbers like this! :) And the answer was, not having
               | a life outside of grad school.
        
               | jhgb wrote:
               | Grad school doesn't last forty years though...or does it?
        
               | light_hue_1 wrote:
               | I should hope not!
               | 
               | Also, 40 years? 1000000/40/52 ~> You're assuming the
               | average developer writes 500 lines of code per week? That
               | seems absurdly slow.
        
               | jhgb wrote:
               | Well, you _did_ say  "several millions", so that would be
               | more like 2000 lines. And depending on the environment,
               | I'm aware of many people who do much less (not of their
               | own volition), so I have little faith in a long-term
               | average being _this_ high. I 'll have to take a look that
               | what Capers Jones wrote on this...
        
               | xxpor wrote:
               | I'm lucky if I write 500 lines of code a quarter these
               | days....
        
               | funcDropShadow wrote:
               | > But languages are absolutely slow or fast! There are
               | fast Schemes and Lisps and there are slow ones.
               | 
               | You are contradicting yourself. If languages instead of
               | implementations were slow or fast, then their would not
               | be fast and slow Schemes and Lisps. Scheme would be
               | either slow or fast.
               | 
               | Actually, I would go even further than saying only
               | implementations are slow or fast, they are slow or fast
               | for certain use cases.
               | 
               | > There is simply no efficient implementation of Elisp
               | possible as it stands and as it is used today. Even with
               | JIT compiling Elisp performance is simply wretched.
               | 
               | I agree in so far as there will --- probably --- never be
               | an Elisp implementation which can run numeric intensive
               | code as fast as the best Fortran or C compiler for this
               | task. But it is certainly possible to improve the
               | performance of ELisp even more than native-comp branch
               | did. The question is whether there are people capable and
               | willing to invest the time to develop that and whether
               | spending that time on the language implementation is the
               | most useful way to spend that time.
        
               | light_hue_1 wrote:
               | > You are contradicting yourself. If languages instead of
               | implementations were slow or fast, then their would not
               | be fast and slow Schemes and Lisps. Scheme would be
               | either slow or fast.
               | 
               | You are unfamiliar with the huge differences between what
               | counts as a "Scheme" or a "Lisp". Neither "Scheme" or
               | "Lisp" are a language, they're language families. The
               | difference between Schemes is larger than the difference
               | between say C and Ocaml, or Haskell and Javascript.
               | 
               | Depending on what features a particular Scheme or Lisp
               | has, it can range from insanely fast (like, faster than
               | an optimizing C compiler), to mediocre (like Python), to
               | dirt slow, like current Elisp. It all depends on what the
               | language has, and how it encourages you to write code.
               | For example, having a type system tends to make your
               | language very fast.
               | 
               | > Actually, I would go even further than saying only
               | implementations are slow or fast, they are slow or fast
               | for certain use cases.
               | 
               | Compilers are not magic. And compiler technology has not
               | fundamentally advanced for decades now. There are basic
               | limits to what a compiler can do. Some language features
               | simply destroy performance, and the lack of some language
               | features prevent compilers from getting good performance.
               | And then, yes, there is also style. For example, relying
               | heavily on language features that are inherently slow,
               | will do you no favors.
               | 
               | Elisp is the pinnacle of a terrible language used in a
               | terrible way. It lacks all features that make languages
               | fast. It has plenty of features to defeat optimizations
               | and preclude having any fast implementations. And people
               | write Elisp in a gory style that makes everything worse.
               | 
               | > I agree in so far as there will --- probably --- never
               | be an Elisp implementation which can run numeric
               | intensive code as fast as the best Fortran or C compiler
               | for this task. But it is certainly possible to improve
               | the performance of ELisp even more than native-comp
               | branch did. The question is whether there are people
               | capable and willing to invest the time to develop that
               | and whether spending that time on the language
               | implementation is the most useful way to spend that time.
               | 
               | I don't care about numerical code. I care about the fact
               | that emacs is dirt slow.
               | 
               | It's been many decades now. Elisp performance has barely
               | budged. Even the native branch only marginally improved
               | things in some edges cases. There is zero evidence that
               | more effort for faster implementations will go anywhere.
               | 
               | In general. More developer time doesn't meaningfully
               | speed up a language even on the timespan of decades; this
               | means like even say a huge effort, a millenium worth of
               | hours of developer time (100 developers full time for 10
               | years), makes no serious difference to the performance of
               | the average app running on the JVM (a few percent), it
               | mostly just patches edge cases. It's the same in Haskell.
               | GHC 7, from 10 years ago, is marginally slower than GHC
               | 9.4 if you run the same large app in both.
               | 
               | What makes a difference to performance is changing the
               | language. Adding language features that the compiler can
               | understand (that's why say, Haskell code is far faster
               | today than it was 10 years ago, it's a different
               | language, with different features, that we write in a
               | different way).
        
               | jhgb wrote:
               | Then the codebase needs to fully (or as much as feasible)
               | transition to the use of lexical bindings. It's not like
               | we don't know if it will work; Common Lisp supports
               | dynamic variables but you don't pay for them unless you
               | actually use them, and good implementations of CL are
               | fast enough. So what exactly is it that prevents the
               | Emacs Lisp code base from becoming fast enough by
               | abandoning dynamic variables wherever it can? By all
               | rights it should not be any slower than Common Lisp at
               | that point, unless some other obstacle has somehow eluded
               | my attention.
        
               | nicoburns wrote:
               | > Languages are not slow or fast; their implementations
               | are.
               | 
               | Right, but languages have finite extant implementations.
               | If a language has no fast implementations then it's
               | reasonable to call it slow.
        
           | zdragnar wrote:
           | > It is therefore up to you, to use the proper package
           | 
           | This is the single biggest reason I don't use emacs. I have
           | yet to get a stable installation with the necessary behaviors
           | and tools I need to make memorizing all the chords worth the
           | effort.
           | 
           | I've tried spacemacs, doom and from scratch, and have never
           | been satisfied or gotten to the point where coding is as
           | productive as VScode for me.
        
           | yakubin wrote:
           | For me the most frequent source of freezes was Tramp. It led
           | me to ditch Emacs for VSCode (with the remote editing
           | extension) at least for my dayjob (I still use Emacs for my
           | own projects). Tramp is an official built-in package, so it's
           | not as if I downloaded a random package from GitHub.
        
             | [deleted]
        
           | jhoechtl wrote:
           | As an innocent user I tell you that LSP mode just works
           | whereas Eglot needs tailoring to be a joy to use.
        
           | dotancohen wrote:
           | I just got into emacs last year, for Org mode. Startup times
           | drive me crazy.
           | 
           | What would be the correct way to configure my .emacs file to
           | e.g. check for package updates in a background process?
        
             | alex_smart wrote:
             | Don't check for package updates during startup? Setup a
             | cron job to upgrade the packages while you are asleep?
        
             | complex1314 wrote:
             | Use emacsclient and have a emacs server running at all
             | times. Super fast startup times, you can even use
             | emacsclient -nw (or make an alias 'e' for that) in the
             | terminal for fast edits with instantaneous startup.
             | 
             | You could also make a script that starts emacs as a client
             | only if a server already is running
             | #!/bin/sh       if [ "$#" -eq 0 ]       then         echo
             | "Starting new Emacs process ..." >&2         nohup emacs >
             | /dev/null 2>&1 &       elif emacsclient -n "$@" 2>
             | /dev/null       then         echo "Opened $@ in Emacs
             | server" >&2       else         echo "Opening $@ in a new
             | Emacs process ..." >&2         nohup emacs "$@" > /dev/null
             | 2>&1 &       fi
             | 
             | (Copied from an emacs starter kit but don't remember
             | which...)
        
               | massysett wrote:
               | This is really "just leave Emacs running all the time,"
               | which is more of a workaround or an acceptance of "fit
               | your workflow around Emacs" than it is truly a solution,
               | which would be to reduce startup times.
        
               | tom_ wrote:
               | Why do you quit though? I don't quit other programs...
               | why is Emacs different?
        
               | massysett wrote:
               | I quit and restart Vim dozens of times daily.
               | 
               | I'm not saying there's something wrong with leaving Emacs
               | running. But it's a workaround. When I used Emacs,
               | startup time was not a problem. But I didn't use a bunch
               | of packages.
        
               | joseph8th wrote:
               | Once it starts it does almost nothing unless you're using
               | it, and then it's still a lightweight document editor,
               | not an Electron app
        
             | NeutralForest wrote:
             | You should use `use-package` to manage your packages and
             | defer their loading to when you use them. I have over 100
             | packages in my init.el and my Emacs loads in less than a
             | second.
        
             | kwhitefoot wrote:
             | Why does Emacs startup time bother people so much? It's
             | pretty quick for me and only happens once every few months
             | anyway.
        
             | BeetleB wrote:
             | Don't do automatic package updates. It's a sure way to
             | continually break things.
        
             | hierandthere wrote:
             | How often do you start Emacs? I do that maybe once a week.
        
             | contravariant wrote:
             | Using Doom emacs was the easiest way for me to get fast
             | loading times. It provides some sane defaults that should
             | be pretty fast in most cases. It might be worth checking
             | out.
        
           | jonpalmisc wrote:
           | Another vouch for Eglot here. Seems smoother and just nicer
           | overall compared to lsp-mode, not to mention better
           | integration with Emacs. I switched to Eglot a while back and
           | haven't looked back.
        
           | taeric wrote:
           | Glad to see this as the top response here. I was rushing to
           | click reply so that I could point out that async has been a
           | thing for Emacs for a long long time. Compilation mode is my
           | goto example for how that can work.
        
       | tgbugs wrote:
       | One big challenge for multi-threaded Emacs is that there are many
       | elisp libraries and common patterns around buffer modification
       | that make implicit assumptions about sequential and exclusive
       | execution.
       | 
       | The various race conditions that would appear in a multithreaded
       | context would be a nightmare to debug because they would likely
       | only occur sporadically and would be hard to reproduce. I would
       | love to be wrong about this, but I see it as a major obstacle
       | that will likely need to be sandboxed (as was done with lexical
       | scoping).
       | 
       | For an example of how hard these kinds of issues could be to
       | debug look no further than the incredible difficult that the
       | undo-tree author had in debugging a race condition with the
       | garbage collector. It took years.
       | 
       | In the context of this piece, having a buffer mutex makes certain
       | use cases for multi-threading impossible, for example dividing
       | the buffer up into chunk equal to the number of cores and running
       | a regexp over each chunk.
        
       | melony wrote:
       | Note that Clojure offers multiple concurrency systems, the
       | default STM is not particularly performant and doesn't scale very
       | well. You are better off calling into Project Loom for concurrent
       | code.
        
       | Thaxll wrote:
       | Clojure is memory safe and no data races possible?
        
         | melony wrote:
         | Memory safe, perhaps, but data races are definitely possible.
         | The main issue is that their STM system doesn't scale very
         | well. It is good enough if you want to keep a simple CRUD GUI
         | in sync but don't expect to be building high performance web
         | servers anytime soon with Clojure atomics. You can't just
         | create and throw those around willy-nilly like Goroutines.
         | Clojure people doesn't like talking about the language's
         | weaknesses but I have seen quite a few Clojure projects get
         | rewritten because of maintenance cost and runtime
         | inefficiencies. Project Loom is the best option right now for
         | scalable Clojure concurrency/parallelism.
        
           | lilactown wrote:
           | STM, atomics and channels are all different things that can
           | be use to build different kinds of systems, so I think it's
           | good to disambiguate them when talking about concurrency
           | problems and their tradeoffs.
           | 
           | Clojure' STM is basically unused. It's a suite of functions
           | and a container type `ref` that allows you to do transactions
           | in memory and keep everything consistent within the view of a
           | transaction. The overhead required to do the book keeping for
           | these transactions is often not worth it for most use cases
           | in practice.
           | 
           | Clojure also, as an alternative, gives you `atom` which is a
           | type that implements a simple thread safe compare-and-swap.
           | This ends up being sufficient for many cases of sharing state
           | between threads. When combined with Clojure's immutable data
           | structures, one can often use them as a simple in memory
           | database.
           | 
           | Those two things are about sharing memory, but has nothing to
           | do with what the article talks about: green threads.
           | 
           | clojure.core.async, as the article succinctly explains,
           | allows you to create "goroutines" or green threads which are
           | then multiplexed across some number of OS threads. This can
           | allow you to create many more threads for computation than
           | you have OS threads, and combined with thread locals and
           | atoms can allow one to build large scale systems.
           | 
           | Clojure's STM and atomics are sort of a non-sequitur from
           | what the article is talking about
           | 
           | Now as for downsides of Clojure, there are plenty of gotchas
           | in practice that can lead people to issues with the three
           | things above:
           | 
           | * STM is slow and rarely useful compared to regular atomics
           | 
           | * atoms CAS assumes you are using immutable data structures
           | 
           | * core.async has a lot of sharp edges, including lack of
           | first-class error handling and the fact that doing
           | synchronous I/O on a go routine can end up starving the
           | thread pool they are running on
           | 
           | I've never built a high performance web server, but I imagine
           | it's possible with Clojure; it would probably require you to
           | probably eschew immutable data structures within the plumbing
           | (for performance) and use an async I/O framework along with
           | core.async to get competitive with a language like go. For
           | shared memory, you probably would end up eschewing compare-
           | and-swap for something more bare bones like locks, which you
           | have access to via Java interop. At that point, you may
           | wonder why you even chose Clojure in the first place instead
           | of using Java directly. :D
           | 
           | Project Loom really only helps solve the problem that
           | core.async is trying to solve, and applications would still
           | make use of atomics like `atom` and basic Java atomic values.
           | My hope is that it makes it easier to do I/O, since it sounds
           | like along with loom fibers the project is adding first class
           | support for suspending and resuming on fundamental I/O
           | operations. Time will tell.
        
       ___________________________________________________________________
       (page generated 2022-05-30 23:00 UTC)