Skip to content

Instantly share code, notes, and snippets.

@jdtsmith
Last active December 28, 2022 19:23
Show Gist options
  • Select an option

  • Save jdtsmith/0c35675ec33be1402fab60fe6cbd4d0c to your computer and use it in GitHub Desktop.

Select an option

Save jdtsmith/0c35675ec33be1402fab60fe6cbd4d0c to your computer and use it in GitHub Desktop.
Where precisely can Emacs take control of execution to deliver async process output to your filter-function?
(defvar-local still-waiting nil
"Whether we are still waiting for a chunk of process output to complete.")
(defun my-worker-1 (process)
"Do some work and yield to PROCESS output."
(do-some-sensitive-calculation)
(sit-for 1) ; A) output can interrupt me here
(another-sensitive-buffer-manipulation) ; B) what about here?
(my-worker-2 process))
(defun my-worker-2 (process)
"Do some work and communicate with PROCESS."
(heavy-calc1) ; C) can these simple calc-only calls themselves be interrupted?
(heavy-calc2) ; D) how about *between* the two calls?
(process-send-string proc "I'm done!") ; E) presumably right here can be
(my-worker-3)
(while still-waiting
(accept-process-output process 0.1 nil 1) ; F) obviously here
(sit-for 0.02))) ; G) and here
(defun my-worker-3 ()
"Do more work, entirely unrelated to the process."
(do-something-entirely-unrelated-to-the-process)) ; H) but can this function or its internal calls be interrupted?
@jdtsmith

Copy link
Copy Markdown
Author

But you can yield to that loop at will, to let other tasks run (async output arrive) at any time, in a predictable manner. Whereas Emacs may process async output at more unexpected times.

No, that's not true. It is exactly the same situation in Emacs. Note that async/await is just syntactic sugar.

do_something_heavy()
some_output(function(new_output) {
   do_something_with(new_output)
   other_output(function(other_output) {
      ...
   })
})

Right. But in emacs, do_something_with(new_output) may itself lead to code-paths which produce process output. While this is true in Python/JS, it seems (based on admittedly limited experience) way less common. Maybe "async hygiene" is the right idea.

Vice versa you can write a macro in Emacs which performs the same async/await transformation for a block of code. Not sure how this package is called (aio?). If you write the exact same code in Emacs, "await" will also yield to the outer event loop "at will".

I am not sure where your misconception lies here. The complication in Emacs is only that you can locally start additional event loops, e.g., via sit-for. This is what makes Emacs somewhat "more cooperative" and maybe "less intuitive".

This exactly. And that various emacs internals effectively call "await process_output()" without regard for whether you are prepared to accept it at that moment. But if the list of such internals is predictable, you can work around it (and, as you say, use it to your advantage).

@minad

minad commented Dec 28, 2022

Copy link
Copy Markdown

And that various emacs internals effectively call "await process_output()" without regard for whether you are prepared to accept it at that moment.

That's not what they do. They start a new local event loop, they are blocking. But yes, if one ensures that no such blocking functions are called, everything should be predictable.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment