Sök…


grundläggande kanaloperationer: skapa, sätta, ta, stänga och buffra.

core.async handlar om att göra processer som tar värden från och sätter värden i kanaler .

(require [clojure.core.async :as a])

Skapa kanaler med chan

Du skapar en kanal med chan funktionen:

(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

Sätta värden i kanaler med >!! och >!

Du lägger värden i en kanal med >!! :

(a/>!! my-channel :an-item)

Du kan lägga till valfritt värde (strängar, nummer, kartor, samlingar, objekt, till och med andra kanaler, etc.) i en kanal, utom nil :

;; WON'T WORK
(a/>!! my-channel nil)
=> IllegalArgumentException Can't put nil on channel

Beroende på kanalens buffert, >!! kan blockera den aktuella tråden.

(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.
  )

Inifrån ett (go ...) block kan du - och borde - använda a/>! istället för a/>!! :

 (a/go (a/>! ch :item))

Det logiska beteendet kommer att vara detsamma som a/>!! , men bara den logiska processen för goroutinen kommer att blockeras i stället för den faktiska OS-tråden.

Med hjälp av a/>!! insidan av ett (go ...) block är ett antimönster:

;; NEVER DO THIS
(a/go 
  (a/>!! ch :item))

Ta värden från kanaler med <!!

Du tar ett värde från en kanal med <!! :

;; 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

Om inget objekt är tillgängligt i kanalen, a/<!! kommer att blockera den aktuella tråden tills ett värde läggs i kanalen (eller kanalen stängs, se senare):

(def ch (a/chan))
(a/<!! ch) ;; blocks until another process puts something into ch or closes it

Inifrån ett (go ...) block kan du - och borde - använda a/<! istället för a/<!! :

 (a/go (let [x (a/<! ch)] ...))

Det logiska beteendet kommer att vara detsamma som a/<!! , men bara den logiska processen för goroutinen kommer att blockeras i stället för den faktiska OS-tråden.

Med hjälp av a/<!! insidan av ett (go ...) block är ett antimönster:

;; NEVER DO THIS
(a/go 
  (a/<!! ch))

Stänger kanaler

Du stänger en kanal med a/close! :

(a/close! ch)

När en kanal är stängd, och all data i kanalen har uttömts, kommer alltid tar tillbaka 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

Asynkron sätter med put!

Som ett alternativ till a/>!! (vilket kan blockera), du kan ringa a/put! att sätta ett värde i en kanal i en annan tråd, med ett valfritt återuppringning.

(a/put! ch :item)
(a/put! ch :item (fn once-put [closed?] ...)) ;; callback function, will receive 

I ClojureScript är det inte möjligt att blockera den aktuella tråden, a/>!! stöds inte och put! är det enda sättet att lägga in data i en kanal utanför ett (go) -block.

Asynkron tar med take!

Som ett alternativ till a/<!! (vilket kan blockera den aktuella tråden), du kan använda a/take! för att ta ett värde från en kanal asynkront, vidarebefordra det till ett återuppringning.

(a/take! ch (fn [x] (do something with x)))

Använd släpp- och glidbuffertar

Med tappning och glidande buffertar, sätter aldrig blockera, men när bufferten är full förlorar du data. Att släppa bufferten förlorar den senaste uppgiften, medan glidande buffertar förlorar den första uppgiften

Släpp buffertexempel:

(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

Exempel på glidbuffert:

(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


Modified text is an extract of the original Stack Overflow Documentation
Licensierat under CC BY-SA 3.0
Inte anslutet till Stack Overflow