|
(ns core-async-alts-fastest.2-alts-google-fastest |
|
(:require [clojure.core.async :as async :refer [<!! >!! <! >! go onto-chan close! timeout chan alt! alts! alt!!]] |
|
)) |
|
|
|
(defn fake-search [kind] |
|
;; 这里的两个参数外部何时调用? |
|
(fn [c query] |
|
(go |
|
(<! (timeout (rand-int 100))) |
|
(>! c [kind query])))) |
|
|
|
;; 三个服务都有双备份,谁快用谁 |
|
(def web1 (fake-search :web1)) |
|
(def web2 (fake-search :web2)) |
|
(def image1 (fake-search :image1)) |
|
(def image2 (fake-search :image2)) |
|
(def video1 (fake-search :video1)) |
|
(def video2 (fake-search :video2)) |
|
|
|
;; 两个服务中选择最快的那个 |
|
;; (fastest "clojure" web1 web2) |
|
(defn fastest [query & replicas] |
|
(let [c (chan)] |
|
(doseq [replica replicas] |
|
;; (fake-search :web1 c "clojure") |
|
(replica c query)) |
|
;; 返回内容 [:web1 "clojure"] OR [:web2 "clojure"] |
|
;; 获取c, 谁先往channel写入成功返回谁 |
|
c)) |
|
|
|
;; google search |
|
;; 查询3个服务,每个服务都有2个备份 |
|
(defn google [query] |
|
(let [c (chan) |
|
t (timeout 80)] |
|
;; 这里向c 写入3次不同的服务; 每个fastest只有一个channel, 两个中只有一个写成功 |
|
(go (>! c (<! (fastest query web1 web2)))) |
|
(go (>! c (<! (fastest query image1 image2)))) |
|
(go (>! c (<! (fastest query video1 video2)))) |
|
(go (loop [i 0 ret []] |
|
(if (= i 3) |
|
ret |
|
;; 这里 v 是什么? |
|
;; @problems |
|
(recur (inc i) (conj ret |
|
;; alt 需要确保后面的参数是偶数, 但是我不知道这里的v有什么用 |
|
;; 我觉得还是alts 容易理解 |
|
#_(alts! [c t]) |
|
;; @problems |
|
;; 下面括号干啥? |
|
(alt! [c t] ([v] v)) ;; what's the fuck of v? |
|
))))))) |
|
|
|
(comment |
|
(<!! (google "clojure")) |
|
) |
|
|
|
;; from netty socket |
|
;; 下面这个和google上面的有点类似, 即alt! 后面是偶数 |
|
;; |
|
(defn- write-loop |
|
"Returns a channel containing the result of a loop that sends |
|
messages over the WebSocket when items are placed on the |
|
write-channel. |
|
|
|
If an error occurs or the remote endpoint is closed, the exception |
|
or status code and reason are given as the result. When one of |
|
these events occurs, it closes the write channel so that no new |
|
messages may be attempted. Values already on the write channel that |
|
have yet to be sent to the client will remain on the write channel |
|
so that the user can decide what to do with them. |
|
|
|
When anything would stop writing, the read-channel is also closed. |
|
|
|
If the user closes the write-channel, the session will be closed |
|
with it. |
|
|
|
Sessions will be closed with status code 1000 (CLOSE_NORMAL)." |
|
[^Session session read-channel write-channel result-channel] |
|
(let [remote (.getRemote session)] |
|
(go-loop [] |
|
;; here |
|
(alt! |
|
result-channel |
|
;; 这边括号干啥? |
|
;; @problems |
|
([v] |
|
;; The session is already closed, so just deal with the |
|
;; read and write channels. |
|
(close! write-channel) |
|
(close! read-channel) |
|
v) |
|
write-channel |
|
([message] |
|
(if (nil? message) |
|
(do (.close session) (close! read-channel)) |
|
(do |
|
;; Errors inside of the sendString call are passed to |
|
;; onWebSocketError so you don't need to capture them |
|
;; here |
|
(.sendString remote message) |
|
(recur)))) |
|
:priority true)))) |