emacs-devel
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

Re: Concurrency via isolated process/thread


From: Hugo Thunnissen
Subject: Re: Concurrency via isolated process/thread
Date: Tue, 18 Jul 2023 14:14:19 +0200
User-agent: Mozilla/5.0 (X11; Linux x86_64; rv:102.0) Gecko/20100101 Thunderbird/102.13.0


On 7/18/23 07:25, Ihor Radchenko wrote:
Hugo Thunnissen <devel@hugot.nl> writes:

Yes, most of Elisp is about text processing. But when we really need to
utilize asynchronous code, it is usually not about reading/writing text
- it is about CPU-heavy analysis of text. This analysis is what truly
needs async threads.
I am skeptical that there are all that many use cases for the
asynchronous analysis of text in buffers that are currently being
edited.
Org does it via idle timers.
Also, consider searching across many buffers - that's a legitimate use
case. Think about AG/RG and other multi-threaded text searchers.
If the buffers are also structured and need to be parsed, we arrive at
the situation when parallelism can be quite useful.

True, for that scenario parallelism could be useful.


... Correct me if I'm wrong, AFAIU programs that analyze text as it
is being edited will usually need to re-parse after every edit anyways,
making a parse during the edit itself not all that useful: After all,
the result is no longer accurate for the buffer contents by the time it
becomes available. A synchronous parser can probably do just as good of
a job in such a scenario, as long as it is interruptible by user input.
No. It still makes sense to re-parse incrementally before the point
where the edits are being made. For example, Org parser has to trash
everything that may theoretically be affected by current edits and
re-parse later, synchronously, on demand. This trashing sometimes
involve rather big chunks of text, and it would significantly speed
things up if we could do part of the incremental parsing in parallel.

I see. I am not familiar with org-mode's code so I'll take your word for it.

From my own limited experience, I think that most of the time the user isn't looking for "instant" feedback, but just wants feedback to appear shortly after they stop typing. I would expect a parser, even if not incremental, to be able to parse most buffers within 10 to maybe 200 milliseconds. I think this is an acceptable wait time for feedback granted that the parse is interruptible by user input, so that it can never make the user wait for an unresponsive Emacs. Having less wait time through the use of multi threading might be slightly nicer, but I don't see it making that much of a difference for the user experience in most modes. Would you agree with that as a general statement?

I'm not familiar with the C core at all, do you think it might be more
realistic to add a little more facilities for asynchronous data streams
than to rework the execution model of Emacs to add multi threading? I'm
mainly thinking of something like "channels" or "queues" for lisp
objects, with an easy to use scheduling mechanism that makes it
straightforward for people to not stall the main thread for too long.
AFAIK, sentinels do this already. Of course, they are quite basic.
As for queues, see https://emacsconf.org/2022/talks/async/

Sentinels are for external processes. I was thinking more in the vain of a queue that is owned by two lisp threads, where one thread can write and prepare input for the other, and the other thread yields as long as there is no new input to process. When a thread receives an input message from the other, it will come alive at the next idling moment and process the queue while yielding in between messages. This would make it easier to process data in chunks without halting the main thread long enough to bother the user, as long as the main thread is prioritized over others.


And another (very) nice to have feature: asynchronous filesystem IO.
Consider the code below which I use in a package I'm working on. My
package reads and parses a large amount of files in the background
within a short time frame. Parsing/processing the files in a timely
manner is never really an issue, but the blocking IO of
`insert-file-contents' does often take so long that it is  impossible to
not have the user notice, even if polling `input-pending-p' and yielding
in between operations.
Well. I have an opposite problem when `read' takes second to read few Mb
of Elisp data, while inserting it into a temporary buffer is instant.

Also, did you actually profile your use case?

I am ashamed to admit that I did not, I did not know about the profiler at the time so I just did guesswork until I seemed to be getting results. There seemed to be a noticeable difference at the time, but at the moment I'm having trouble reproducing it, so needless to say I did not find a large difference re-running both solutions with the profiler enabled. I did make some other large changes in the codebase since I made this change, so it could very well be that the thing that made Emacs hang at the time was not filesystem IO at all. Or there was something else going on with the specific files that were being parsed (I don't remember which folder I did my tests on). Sorry for being the typical guy who makes claims about performance without doing his due diligence ;)

I still suspect that async filesystem IO could make a considerable difference in some scenarios. My package is for PHP projects and it is not unheard of for PHP files to be edited over network mounts where IO could have a lot more latency. For example, some people have asked me whether my package works over tramp. I haven't profiled this scenario yet as I have to make some tweaks first to make it work at all, but I fear that blocking on `insert-file-contents' may not be ideal in that scenario.

And then there also is `directory-files-recursively':

         457  77%         - phpinspect-index-current-project
         457  77%          - let*
         371  63%           - if
         371  63%            - progn
         371  63%             - let
         371  63%              - while
         371  63%               - let
         371  63%                - if
         371  63%                 - progn
         371  63%                  - let
         371  63%                   - while
         371  63%                    - let
         371  63%                     - if
         361  61%                      - progn
         361  61%                       - let*
         312  53%                        - if
         312  53%                         - progn
         308  52%                          - maphash
         308  52%                           - #<lambda -0x2edd06728f18cc0>
         308  52%                            - let
         305  51%                             - if
         305  51%                              - progn
         305  51%                               - phpinspect-al-strategy-fill-typehash
         305  51%                                - apply
         292  49%                                 - #<lambda 0x725f4ad90660>
         292  49%                                  - progn
         292  49%                                   - let
         292  49%                                    - let
         292  49%                                     - while
         292  49%                                      - let
         292  49%                                       - let
         172  29%                                        - while
         172  29%                                         + let
         120  20%                                        - phpinspect-fs-directory-files-recursively
         120  20%                                         - apply
         120  20%                                          - #<lambda 0xf3386f2a7932164>
         120  20%                                           - progn
         120  20%                                           - progn
         120  20%                                            - directory-files-recursively           79  13%                                             - directory-files-recursively           21   3%                                              - directory-files-recursively
          11 1% directory-files-recursively
           4   0% sort
           3   0% file-remote-p






reply via email to

[Prev in Thread] Current Thread [Next in Thread]