The Racket community, and even more so the design of Racket
concurrency APIs, is very strongly influenced by the academic side of
Racket. As far as I can tell, structured concurrency is fairly close
to what is traditionally called the fork/join model. Concurrency in
Racket is usually structured in a somewhat different way, around
first-class events and channels. First-class events were originally
created in Concurrent ML, and the basic idea is that you can package
up things that you might think of as concurrency operations (such as
`select` in Go) and turn them into _values_ which you can then further
synchronize on.
Here's how I would write the Happy Eyeballs program in Racket:
#lang racket/base
(define DELAY 300)
(require racket/tcp racket/match racket/set)
(define threads (mutable-set))
(define (connect hosts)
(let loop ([hosts hosts] [chans null])
(cond [(null? hosts)
#f]
[else
(define ch (make-channel))
(define t (thread (lambda ()
(with-handlers ([exn:fail? (λ _
(channel-put ch #f))])
(define-values (in out) (tcp-connect
(car hosts) 80))
(channel-put ch (cons in out))))))
(set-add! threads t)
(match (apply sync (alarm-evt (+ (current-milliseconds)
DELAY)) ch chans)
[(cons in out) ;; success
(for ([t threads]) (kill-thread t))
(cons in out)]
[#f ;; error
;; thread is dead, don't need to kill it
;; don't need to remember this channel
(loop (cdr hosts) chans)]
[_ ;; timeout
;; ask the next iteration to sync on this channel too
(loop (cdr hosts) (cons ch chans))])])))
I think that this does the right thing, although it's not actually
using IP addresses and the IP-level operations, but hostnames and TCP
sockets.
One other thing I would note. This is simple, but even simpler would
be to package up `tcp-connect` as an event, the way `tcp-accept-evt`
works. Then you could write something like:
(apply sync (for/list ([(i h) hosts]) (replace-evt (alarm-evt (+
(current-milliseconds) (* DELAY i)))
(lambda _ (tcp-connect-evt h 80)))))
Sam
On Wed, Oct 9, 2019 at 1:43 PM jab <[email protected]> wrote:
>
> So far from this thread, it seems the idea of Structured Concurrency hasn’t
> yet made it into the Racket world. I’ll be interested to see if it gets
> adopted in Racket in the future (or at least better understood) as its
> adoption grows elsewhere.
>
> In the meantime, in case it helps illustrate the idea to anyone else still
> interested, check out the talk I linked to previously showing an
> implementation of Happy Eyeballs using structured concurrency. Or just read
> it directly from the Trio source once you understand what a nursery and a
> cancel scope are:
> https://github.com/python-trio/trio/blob/master/trio/_highlevel_open_tcp_stream.py
>
> (RFC 6555 Happy Eyeballs is like a Hello World of the problem space that
> structured concurrency is addressing, so this is an illustrative example.)
>
> If there is some blessed Racket implementation of Happy Eyeballs, it could be
> useful to compare – for correctness, completeness, obviousness, and elegance.
>
> --
> You received this message because you are subscribed to the Google Groups
> "Racket Users" group.
> To unsubscribe from this group and stop receiving emails from it, send an
> email to [email protected].
> To view this discussion on the web visit
> https://groups.google.com/d/msgid/racket-users/ed325f57-d7e3-47dc-a2e7-76fc0af1ff50%40googlegroups.com.
--
You received this message because you are subscribed to the Google Groups
"Racket Users" group.
To unsubscribe from this group and stop receiving emails from it, send an email
to [email protected].
To view this discussion on the web visit
https://groups.google.com/d/msgid/racket-users/CAK%3DHD%2Baw3vS5k%2BM0qdNdrnazVxbTNkfqWE7-__E1Lx35TsUqjQ%40mail.gmail.com.