Recherche…


opérations de base du canal: création, mise en place, prise, fermeture et tampons.

core.async consiste à créer des processus qui prennent des valeurs et placent des valeurs dans des canaux .

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

Créer des canaux avec chan

Vous créez un canal en utilisant la fonction 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

Mettre des valeurs dans les canaux avec >!! et >!

Vous mettez des valeurs dans un canal avec >!! :

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

Vous pouvez mettre n'importe quelle valeur (chaînes, nombres, cartes, collections, objets, même d'autres canaux, etc.) dans un canal, sauf le nil :

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

Selon le tampon de la chaîne, >!! peut bloquer le thread en cours.

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

A l'intérieur d'un bloc (go ...) , vous pouvez et devez utiliser a/>! au lieu d' a/>!! :

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

Le comportement logique sera le même a/>!! , mais seul le processus logique de la goroutine sera bloqué à la place du thread OS réel.

Utiliser a/>!! l'intérieur d'un bloc (go ...) est un anti-pattern:

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

Prendre des valeurs de canaux avec <!!

Vous prenez une valeur d'un canal en utilisant <!! :

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

Si aucun élément n'est disponible dans le canal, a/<!! va bloquer le thread actuel jusqu'à ce qu'une valeur soit placée dans le canal (ou que le canal soit fermé, voir plus loin):

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

A l'intérieur d'un bloc (go ...) , vous pouvez et devez utiliser a/<! au lieu d' a/<!! :

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

Le comportement logique sera le même a/<!! , mais seul le processus logique de la goroutine sera bloqué à la place du thread OS réel.

Utiliser a/<!! l'intérieur d'un bloc (go ...) est un anti-pattern:

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

Canaux de fermeture

Vous fermez une chaîne avec a/close! :

(a/close! ch)

Une fois qu'un canal est fermé et que toutes les données du canal ont été épuisées, les prises renvoient toujours 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

Asynchrone met avec put!

En alternative à a/>!! (qui peut bloquer), vous pouvez appeler a/put! mettre une valeur dans un canal dans un autre thread, avec un rappel facultatif.

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

En ClojureScript, depuis le blocage du thread en cours n'est pas possible, a/>!! n'est pas supporté et put! est le seul moyen de placer des données dans un canal en dehors d'un bloc (go) .

Asynchrone prend à take!

En alternative à a/<!! (qui peut bloquer le thread en cours), vous pouvez utiliser a/take! pour prendre une valeur d'un canal de manière asynchrone, en le passant à un rappel.

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

Utilisation de tampons de largage et de glissement

Avec les tampons de dépôt et de glissement, ne bloque jamais, mais lorsque le tampon est plein, vous perdez des données. Le tampon de suppression perd les dernières données ajoutées, tandis que les tampons glissants perdent les premières données ajoutées.

Exemple de tampon de suppression:

(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

Exemple de tampon coulissant:

(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
Sous licence CC BY-SA 3.0
Non affilié à Stack Overflow