all messages for Emacs-related lists mirrored at yhetil.org
 help / color / mirror / code / Atom feed
From: Tomas Hlavaty <tom@logand.com>
To: Stefan Monnier <monnier@iro.umontreal.ca>,
	Jim Porter <jporterbugs@gmail.com>
Cc: Karthik Chikmagalur <karthikchikmagalur@gmail.com>,
	Thomas Koch <thomas@koch.ro>,
	"emacs-devel@gnu.org" <emacs-devel@gnu.org>
Subject: Re: continuation passing in Emacs vs. JUST-THIS-ONE
Date: Fri, 17 Mar 2023 01:17:41 +0100	[thread overview]
Message-ID: <87mt4c6xju.fsf@logand.com> (raw)
In-Reply-To: <jwv8rfx3o0k.fsf-monnier+emacs@gnu.org>

Hi Stefan,

On Wed 15 Mar 2023 at 13:48, Stefan Monnier <monnier@iro.umontreal.ca> wrote:
>> I seem to recall that Stefan Monnier (CCed) mentioned having some WIP
>> code to make generator.el easier to use for asynchronous code...
> I think my WiP thingy is very similar to emacs-aio.  I haven't had
> time to work on it and I'd welcome help with it (attached).

Interesting.

From futur.el:

> ;; (futur-let*
> ;;   (exitcode <- (futur-process-make :command cmd :buffer t))
> ;;   (out (buffer-string)) ;; Get the process's output.
> ;;   (cmd2 (build-second-arg-list exitcode out))
> ;;   (otherexit <- (futur-process-make :command cmd :buffer t)))
> ;;  (futur-pure (buffer-string)))

Seems like beautiful lisp code has no futur. :-)

There is something very ugly about this code.
It looks like assembly, 1 dimensional vertical code.
It is hard to see the structure of the code and what it actually does.
I do not think it is practical to write non-trivial code in this style.

Nice lisp code is usually 2 dimensional,
with indentation and top-left to bottom-right direction.
It is usually much clearer to see what is an argument to what
based on the position in the syntax tree.

Is it possible to make the syntax more structured (lispy)?
Meaning tree-like, not list-like?
Something in the spirit of:

(futur-progn
 (futur-process-make
  :command (futur-let ((exitcode (futur-process-make
                                  :command (build-arg-list)
                                  :buffer t)))
             (build-second-arg-list exitcode (buffer-string)))
  :buffer t)
 (buffer-string))

or would it need some fancy syntax rewriting like other async/cps
syntax rewriting libraries?


Second question: I see that futur-wait blocks the whole emacs due to
the while loop.  How can one use futur without blocking emacs?


I usually prefer pull based code as it does not steal control from me.
Lets say I want to do something nontrivial but not block emacs.  I would
split computation into chunks, identify state explicitly and move it to
the heap and suspend the computation without needing to reserve a stack
for it.  I.e. manually write a kind of stream that yields items or nil
as EOF (without syntax rewriting ala generators.el).  I need EAGAIN for
stuff happening asynchronously.  Stuff that blocks simply needs to be
such a small chunk that it does not negatively affect emacs useability.

Unfortunately futur.el does not have executable example so I'll invent
one.

Example (requires lexical bindings): Traverse filesystem, find
*.el files and do something for each one (here I just count the length
of the absolute path for simplicity).  And the whole thing should not
block emacs.

(defun stream-pull-in-background (stream &optional secs repeat)
  (let (timer)
    (setq timer (run-with-timer
                 (or secs 1)
                 (or repeat 1)
                 (lambda ()
                   ;;(message "@@@ polling!")
                   (unless (funcall stream)
                     (cancel-timer timer)))))))

(defun line-stream (buffer)
  ;; yield buffer lines, follow process output if any
  (let (start)
    (lambda ()
      (with-current-buffer buffer
        (save-excursion
          (unless start
            (setq start (point-min)))
          (goto-char start)
          (let ((end (line-beginning-position 2)))
            ;;(message "@@@ %s %s" start end)
            (if (< start end)
                (prog1 (buffer-substring-no-properties
                        start
                        (line-end-position 1))
                  (setq start end))
              (let ((process (get-buffer-process buffer)))
                (if (and process (process-live-p process))
                    'EAGAIN
                  (let ((end (point-max)))
                    (when (< start end)
                      (prog1 (buffer-substring-no-properties start end)
                        (setq start end)))))))))))))

(defun burst-stream (stream &optional secs)
  ;; pull available data during SECS time window
  ;; this is very crude "scheduler" but keeps emacs mostly useable
  (let ((secs (or secs 0.2)))
    (lambda ()
      (when secs
        (let ((z 'EAGAIN)
              (end (+ secs (float-time (current-time)))))
          ;;(message "@@@ burst %s %s:" (float-time (current-time)) end)
          (while (and (< (float-time (current-time)) end)
                      (setq z (funcall stream))
                      (not (eq 'EAGAIN z))))
          (unless z (setq secs nil))
          z)))))

(defun message2-stream (stream)
  (lambda ()
    (let ((x (funcall stream)))
      (when x
        (unless (eq 'EAGAIN x)
          (message "@@@ %s %s" (length x) x))
        x))))

(defun test-buffer (name)
  (let ((b (get-buffer-create name)))
    (with-current-buffer b
      (buffer-disable-undo)
      (erase-buffer))
    b))

(defun test3 (buffer-name command)
  (stream-pull-in-background
   (let ((b (test-buffer buffer-name)))
     (make-process :name buffer-name
                   :command command
                   :buffer b)
     (burst-stream (message2-stream (line-stream b))))))

;;(test3 "test3" '("cat" "/tmp/a.el"))
;;(test3 "test3" '("find" "/home/tomas/mr/" "-type" "f" "-name" "*.el"))
;;(list-processes)
;;(list-timers)


Last question: How would similar functionality be implemented using
futur?

Cheers

Tomas



  reply	other threads:[~2023-03-17  0:17 UTC|newest]

Thread overview: 53+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2023-03-11 12:53 continuation passing in Emacs vs. JUST-THIS-ONE Thomas Koch
2023-03-12  1:45 ` Jim Porter
2023-03-12  6:33   ` tomas
2023-03-14  6:39   ` Karthik Chikmagalur
2023-03-14 18:58     ` Jim Porter
2023-03-15 17:48       ` Stefan Monnier
2023-03-17  0:17         ` Tomas Hlavaty [this message]
2023-03-17  3:08           ` Stefan Monnier
2023-03-17  5:37             ` Jim Porter
2023-03-25 18:42             ` Tomas Hlavaty
2023-03-26 19:35               ` Tomas Hlavaty
2023-03-28  7:23                 ` Tomas Hlavaty
2023-03-29 19:00                 ` Stefan Monnier
2023-04-03  0:39                   ` Tomas Hlavaty
2023-04-03  1:44                     ` Emanuel Berg
2023-04-03  2:09                     ` Stefan Monnier
2023-04-03  4:03                       ` Po Lu
2023-04-03  4:51                         ` Jim Porter
2023-04-10 21:47                       ` Tomas Hlavaty
2023-04-11  2:53                         ` Stefan Monnier
2023-04-11 19:59                           ` Tomas Hlavaty
2023-04-11 20:22                             ` Stefan Monnier
2023-04-11 23:07                               ` Tomas Hlavaty
2023-04-12  6:13                                 ` Eli Zaretskii
2023-04-17 20:51                                   ` Tomas Hlavaty
2023-04-18  2:25                                     ` Eli Zaretskii
2023-04-18  5:01                                       ` Tomas Hlavaty
2023-04-18 10:35                                       ` Konstantin Kharlamov
2023-04-18 15:31                                         ` [External] : " Drew Adams
2023-03-29 18:47               ` Stefan Monnier
2023-04-17  3:46                 ` Lynn Winebarger
2023-04-17 19:50                   ` Stefan Monnier
2023-04-18  2:56                     ` Lynn Winebarger
2023-04-18  3:48                       ` Stefan Monnier
2023-04-22  2:48                         ` Lynn Winebarger
2023-04-18  6:19                     ` Jim Porter
2023-04-18  9:52                       ` Po Lu
2023-04-18 12:38                         ` Lynn Winebarger
2023-04-18 13:14                         ` Stefan Monnier
2023-04-19  0:28                           ` Basil L. Contovounesios
2023-04-19  2:59                             ` Stefan Monnier
2023-04-19 13:25                               ` [External] : " Drew Adams
2023-04-19 13:34                                 ` Robert Pluim
2023-04-19 14:19                                   ` Stefan Monnier
2023-04-21  1:33                                     ` Richard Stallman
2023-04-19  1:11                           ` Po Lu
2023-04-17 21:00                   ` Tomas Hlavaty
2023-03-14  3:58 ` Richard Stallman
2023-03-14  6:28   ` Jim Porter
2023-03-16 21:35 ` miha
2023-03-16 22:14   ` Jim Porter
2023-03-25 21:05 ` Tomas Hlavaty
2023-03-26 23:50 ` Tomas Hlavaty

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=87mt4c6xju.fsf@logand.com \
    --to=tom@logand.com \
    --cc=emacs-devel@gnu.org \
    --cc=jporterbugs@gmail.com \
    --cc=karthikchikmagalur@gmail.com \
    --cc=monnier@iro.umontreal.ca \
    --cc=thomas@koch.ro \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
Code repositories for project(s) associated with this external index

	https://git.savannah.gnu.org/cgit/emacs.git
	https://git.savannah.gnu.org/cgit/emacs/org-mode.git

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.