Ricerca…
operazioni di base del canale: creazione, inserimento, chiusura, chiusura e buffer.
core.async
riguarda i processi che prendono valori e inseriscono valori nei canali .
(require [clojure.core.async :as a])
Creazione di canali con chan
Crei un canale usando la funzione chan
:
(def chan-0 (a/chan)) ;; unbuffered channel: acts as a rendez-vous point.
(def chan-1 (a/chan 3)) ;; channel with a buffer of size 3.
(def chan-2 (a/chan (a/dropping-buffer 3)) ;; channel with a *dropping* buffer of size 3
(def chan-3 (a/chan (a/sliding-buffer 3)) ;; channel with a *sliding* buffer of size 3
Mettere valori in canali con >!!
e >!
Metti i valori in un canale con >!!
:
(a/>!! my-channel :an-item)
Puoi inserire qualsiasi valore (stringhe, numeri, mappe, raccolte, oggetti, persino altri canali, ecc.) In un canale, tranne nil
:
;; WON'T WORK
(a/>!! my-channel nil)
=> IllegalArgumentException Can't put nil on channel
A seconda del buffer del canale, >!!
potrebbe bloccare il thread corrente.
(let [ch (a/chan)] ;; unbuffered channel
(a/>!! ch :item)
;; the above call blocks, until another process
;; takes the item from the channel.
)
(let [ch (a/chan 3)] ;; channel with 3-size buffer
(a/>!! ch :item-1) ;; => true
(a/>!! ch :item-2) ;; => true
(a/>!! ch :item-3) ;; => true
(a/>!! ch :item-4)
;; now the buffer is full; blocks until :item-1 is taken from ch.
)
Dall'interno di un blocco (go ...)
, puoi - e dovresti - usare a/>!
invece di a/>!!
:
(a/go (a/>! ch :item))
Il comportamento logico sarà lo stesso di a/>!!
, ma solo il processo logico della goroutine bloccherà invece del thread effettivo del sistema operativo.
Usando a/>!!
all'interno di un blocco (go ...)
c'è un anti-pattern:
;; NEVER DO THIS
(a/go
(a/>!! ch :item))
Prendendo i valori dai canali con <!!
Prendi un valore da un canale usando <!!
:
;; creating a channel
(def ch (a/chan 3))
;; putting some items in it
(do
(a/>!! ch :item-1)
(a/>!! ch :item-2)
(a/>!! ch :item-3))
;; taking a value
(a/<!! ch) ;; => :item-1
(a/<!! ch) ;; => :item-2
Se nessun elemento è disponibile nel canale, a/<!!
bloccherà il thread corrente fino a quando non viene inserito un valore nel canale (o il canale è chiuso, vedi dopo):
(def ch (a/chan))
(a/<!! ch) ;; blocks until another process puts something into ch or closes it
Dall'interno di un blocco (go ...)
, puoi - e dovresti - usare a/<!
invece di a/<!!
:
(a/go (let [x (a/<! ch)] ...))
Il comportamento logico sarà lo stesso di a/<!!
, ma solo il processo logico della goroutine bloccherà invece del thread effettivo del sistema operativo.
Usando a/<!!
all'interno di un blocco (go ...)
c'è un anti-pattern:
;; NEVER DO THIS
(a/go
(a/<!! ch))
Canali di chiusura
Chiudi un canale con a/close!
:
(a/close! ch)
Una volta che un canale è stato chiuso e tutti i dati nel canale sono stati esauriti, i nil
restituiranno sempre nil
:
(def ch (a/chan 5))
;; putting 2 values in the channel, then closing it
(a/>!! ch :item-1)
(a/>!! ch :item-2)
(a/close! ch)
;; taking from ch will return the items that were put in it, then nil
(a/<!! ch) ;; => :item-1
(a/<!! ch) ;; => :item-2
(a/<!! ch) ;; => nil
(a/<!! ch) ;; => nil
(a/<!! ch) ;; => nil
;; once the channel is closed, >!! will have no effect on the channel:
(a/>!! ch :item-3)
=> false ;; false means the put did not succeed
(a/<!! ch) ;; => nil
Mette asincrono con put!
In alternativa a a/>!!
(che può bloccare), puoi chiamare a/put!
inserire un valore in un canale in un altro thread, con un callback opzionale.
(a/put! ch :item)
(a/put! ch :item (fn once-put [closed?] ...)) ;; callback function, will receive
In ClojureScript, poiché bloccare il thread corrente non è possibile, a/>!!
non è supportato e put!
è l'unico modo per mettere i dati in un canale al di fuori di un blocco (go)
.
Asincrono prende con take!
In alternativa a a/<!!
(che potrebbe bloccare il thread corrente), puoi usare a/take!
per prendere un valore da un canale in modo asincrono, passandolo a un callback.
(a/take! ch (fn [x] (do something with x)))
Usando i buffers dropping e sliding
Con i buffer dropping e sliding, puts non blocca mai, tuttavia, quando il buffer è pieno, si perdono i dati. Il buffer in uscita perde gli ultimi dati aggiunti, mentre i buffer di scorrimento perdono i primi dati aggiunti.
Esempio di buffer di rilascio:
(def ch (a/chan (a/dropping-buffer 2)))
;; putting more items than buffer size
(a/>!! ch :item-1)
=> true ;; put succeeded
(a/>!! ch :item-2)
=> true
(a/>!! ch :item-3)
=> false ;; put failed
;; no we take from the channel
(a/<!! ch)
=> :item-1
(a/<!! ch)
=> :item-2
(a/<!! ch)
;; blocks! :item-3 is lost
Esempio di buffer scorrevole:
(def ch (a/chan (a/sliding-buffer 2)))
;; putting more items than buffer size
(a/>!! ch :item-1)
=> true
(a/>!! ch :item-2)
=> true
(a/>!! ch :item-3)
=> true
;; no when we take from the channel:
(a/<!! ch)
=> :item-2
(a/<!! ch)
=> :item-3
;; :item-1 was lost