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 <jabron...@gmail.com> 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 racket-users+unsubscr...@googlegroups.com.
> 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 racket-users+unsubscr...@googlegroups.com.
To view this discussion on the web visit 
https://groups.google.com/d/msgid/racket-users/CAK%3DHD%2Baw3vS5k%2BM0qdNdrnazVxbTNkfqWE7-__E1Lx35TsUqjQ%40mail.gmail.com.

Reply via email to