[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
Re: Concurrency via isolated process/thread, Po Lu, 2023/07/04
- Re: Concurrency via isolated process/thread, Eli Zaretskii, 2023/07/04
- Re: Concurrency via isolated process/thread, Hugo Thunnissen, 2023/07/17
- Re: Concurrency via isolated process/thread, tomas, 2023/07/18
- Re: Concurrency via isolated process/thread, Ihor Radchenko, 2023/07/18
- Re: Concurrency via isolated process/thread, Po Lu, 2023/07/18
- Re: Concurrency via isolated process/thread, Ihor Radchenko, 2023/07/18
- Re: Concurrency via isolated process/thread,
Hugo Thunnissen <=
- Async IO and queing process sentinels (was: Concurrency via isolated process/thread), Ihor Radchenko, 2023/07/18
- Re: Async IO and queing process sentinels (was: Concurrency via isolated process/thread), Ihor Radchenko, 2023/07/18
- Re: Async IO and queing process sentinels, Michael Albinus, 2023/07/18