Timers take a Duration
timeout and with-deadline take a Duration, made with milliseconds, seconds, minutes or hours; within takes one too. 🤖 Generated with [ECA](https://eca.dev) (anthropic/claude-opus-5-5) Co-Authored-By: eca-agent <git@eca.dev>
This commit is contained in:
parent
3f8c13cc2f
commit
cefa2313ad
1 changed files with 14 additions and 12 deletions
|
|
@ -955,7 +955,7 @@ Functions that may suspend execution—whether waiting on a channel, sleeping, o
|
||||||
@codeblock[#:lang "bjolang"]|{
|
@codeblock[#:lang "bjolang"]|{
|
||||||
(: think (-bjo-> int int))
|
(: think (-bjo-> int int))
|
||||||
(defbjo (think n)
|
(defbjo (think n)
|
||||||
(sync (timeout 50)) ;; wait 50 ms, without holding up a thread
|
(sync (timeout (milliseconds 50))) ;; wait 50 ms, without holding up a thread
|
||||||
(* n n))
|
(* n n))
|
||||||
}|
|
}|
|
||||||
|
|
||||||
|
|
@ -1035,29 +1035,31 @@ Crucially, calling @code{(chan-recv seat)} does not perform the receive immediat
|
||||||
|---------------------------+-------------------------------------------------------------|
|
|---------------------------+-------------------------------------------------------------|
|
||||||
| @code{(chan-recv ch)} | Receives a value from channel @code{ch} |
|
| @code{(chan-recv ch)} | Receives a value from channel @code{ch} |
|
||||||
| @code{(chan-send ch v)} | Sends @code{v} on channel @code{ch} |
|
| @code{(chan-send ch v)} | Sends @code{v} on channel @code{ch} |
|
||||||
| @code{(timeout ms)} | Fires after @code{ms} milliseconds |
|
| @code{(timeout d)} | Fires after the @code{Duration} @code{d} |
|
||||||
| @code{(choose e1 e2 ...)} | Fires when the first of the supplied events occurs |
|
| @code{(choose e1 e2 ...)} | Fires when the first of the supplied events occurs |
|
||||||
| @code{(wrap e f)} | Fires when @code{e} occurs, applying @code{f} to its value |
|
| @code{(wrap e f)} | Fires when @code{e} occurs, applying @code{f} to its value |
|
||||||
}
|
}
|
||||||
|
|
||||||
|
A @code{Duration} is a length of time, made with @code{milliseconds}, @code{seconds}, @code{minutes} or @code{hours}: @code{(timeout (seconds 5))}. It has its unit in its type, so a timer cannot be given a bare number, and one too long for its range raises rather than wrapping round.
|
||||||
|
|
||||||
With these combinators, deadlines and timeouts become simple functions that compose over any event. For instance, we can enforce a response timeout on our card players:
|
With these combinators, deadlines and timeouts become simple functions that compose over any event. For instance, we can enforce a response timeout on our card players:
|
||||||
|
|
||||||
@codeblock[#:lang "bjolang"]|{
|
@codeblock[#:lang "bjolang"]|{
|
||||||
(: within (-> int (Event %a) (Event (Option %a))))
|
(: within (-> Duration (Event %a) (Event (Option %a))))
|
||||||
(defun (within ms ev)
|
(defun (within d ev)
|
||||||
(choose (wrap ev #(Some &))
|
(choose (wrap ev #(Some &))
|
||||||
(wrap (timeout ms) (fun (u) None))))
|
(wrap (timeout d) (fun (u) None))))
|
||||||
|
|
||||||
(: slow-player (-bjo-> (Chan string) void))
|
(: slow-player (-bjo-> (Chan string) void))
|
||||||
(defbjo (slow-player seat)
|
(defbjo (slow-player seat)
|
||||||
(sync (timeout 200))
|
(sync (timeout (milliseconds 200)))
|
||||||
(sync (chan-send seat "7♣")))
|
(sync (chan-send seat "7♣")))
|
||||||
|
|
||||||
(defbjo (main)
|
(defbjo (main)
|
||||||
(def seat (make-chan))
|
(def seat (make-chan))
|
||||||
(spawn (slow-player seat))
|
(spawn (slow-player seat))
|
||||||
(println (sync (within 50 (chan-recv seat)))) ;; None
|
(println (sync (within (milliseconds 50) (chan-recv seat)))) ;; None
|
||||||
(println (sync (within 500 (chan-recv seat)))) ;; (Some 7♣)
|
(println (sync (within (milliseconds 500) (chan-recv seat)))) ;; (Some 7♣)
|
||||||
0)
|
0)
|
||||||
}|
|
}|
|
||||||
|
|
||||||
|
|
@ -1097,14 +1099,14 @@ The top-level @code{main} function acts as an implicit root scope, which is why
|
||||||
|---------------------------------------+------------------------------------------------------------|
|
|---------------------------------------+------------------------------------------------------------|
|
||||||
| @code{(with-scope body ...)} | Waits for child fibers and finalizes open file ports |
|
| @code{(with-scope body ...)} | Waits for child fibers and finalizes open file ports |
|
||||||
| @code{(with-cancel (cancel) body ...)} | Binds a @code{cancel} procedure to signal child fibers |
|
| @code{(with-cancel (cancel) body ...)} | Binds a @code{cancel} procedure to signal child fibers |
|
||||||
| @code{(with-deadline ms body ...)} | Cancels the scope automatically after @code{ms} ms |
|
| @code{(with-deadline d body ...)} | Cancels the scope automatically after the duration @code{d} |
|
||||||
| @code{(with-shield body ...)} | Shields cleanup operations from parent cancellation |
|
| @code{(with-shield body ...)} | Shields cleanup operations from parent cancellation |
|
||||||
}
|
}
|
||||||
|
|
||||||
@codeblock[#:lang "bjolang"]|{
|
@codeblock[#:lang "bjolang"]|{
|
||||||
(: fetch (-bjo-> string void))
|
(: fetch (-bjo-> string void))
|
||||||
(defbjo (fetch name)
|
(defbjo (fetch name)
|
||||||
(sync (timeout 30))
|
(sync (timeout (milliseconds 30)))
|
||||||
(println #"fetched ${name}"))
|
(println #"fetched ${name}"))
|
||||||
|
|
||||||
(: count-up (-bjo-> (Chan int) void))
|
(: count-up (-bjo-> (Chan int) void))
|
||||||
|
|
@ -1115,7 +1117,7 @@ The top-level @code{main} function acts as an implicit root scope, which is why
|
||||||
|
|
||||||
(defbjo (main)
|
(defbjo (main)
|
||||||
;; Both are fetched when this returns, or the deadline raises.
|
;; Both are fetched when this returns, or the deadline raises.
|
||||||
(with-deadline 1000
|
(with-deadline (seconds 1)
|
||||||
(spawn (fetch "a"))
|
(spawn (fetch "a"))
|
||||||
(spawn (fetch "b")))
|
(spawn (fetch "b")))
|
||||||
(println "both done")
|
(println "both done")
|
||||||
|
|
@ -1249,7 +1251,7 @@ If a transaction raises an exception, it writes nothing, and @code{atomically} r
|
||||||
@codeblock[#:lang "bjolang"]|{
|
@codeblock[#:lang "bjolang"]|{
|
||||||
;; A card from the pile, or None after 100 ms.
|
;; A card from the pile, or None after 100 ms.
|
||||||
(sync (choose (wrap (atomically-evt (fun (tx) (take-top tx pile))) Some)
|
(sync (choose (wrap (atomically-evt (fun (tx) (take-top tx pile))) Some)
|
||||||
(wrap (timeout 100) (fun (_) None))))
|
(wrap (timeout (milliseconds 100)) (fun (_) None))))
|
||||||
}|
|
}|
|
||||||
|
|
||||||
Inside a transaction, @code{(tx-or-else tx a b)} runs @code{a}, and if @code{a} retries, undoes its writes and runs @code{b}. If both retry, the whole transaction waits for a change to anything either of them read.
|
Inside a transaction, @code{(tx-or-else tx a b)} runs @code{a}, and if @code{a} retries, undoes its writes and runs @code{b}. If both retry, the whole transaction waits for a change to anything either of them read.
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue