我使用一些Java库来进行非异步的get和post请求。我过去会将这样的请求包装成Future,这解决了我的“等待问题”(即等待响应)。
(defn unchangeable-lib-request [n]
(Thread/sleep 1000)
n)
(defn process [n]
(let [res (atom [])]
(dotimes [i n]
(future (swap! res conj (unchangeable-lib-request i))))
(loop []
(if (> n (count @res))
(recur)
@res))))
(time (process 9))
;; "Elapsed time: 1000.639079 msecs"
;; => [8 7 5 6 4 3 2 1 0]
但是我需要创建数百个请求,这会导致性能问题。我了解了core.async和go块。但如果我将使用这个库中的go块,它不会解决“等待问题”。
(defn unchangeable-lib-request [n]
(Thread/sleep 1000)
n)
(defn process [n]
(let [c (async/chan 10)]
(dotimes [i n]
(async/go
(async/>! c (unchangeable-lib-request i))))
(loop [result []]
(if (> n (count result))
(recur (conj result (async/<!! c)))
result))))
(time (process 9))
;; "Elapsed time: 2001.770183 msecs"
;; => [0 4 1 6 7 2 5 3 8]
Go块只能同时处理8个请求。是否有可能编写一些异步包装器,将go-block停放并提供异步进行100多个请求的能力,而不会相互阻塞?
(defn process [n]
(let [c (async/chan 10)]
(dotimes [i n]
(async/go
(async/>! c (magic-async-parking-wrapper
(unchangeable-lib-request i))))
(loop [result []]
(if (> n (count result))
(recur (conj result (async/<!! c)))
result))))
(time (process 9))
;; "Elapsed time: 1003.2563 msecs"
我了解异步/线程,但似乎这与(future ...)相同。
这可能吗?