exp*_*pez 4 concurrency clojure
我有一些非常独立的任务,我已经使用期货分拆了.这些任务通过core.async/chan将某些事件传递回主应用程序,或者只是与数据库通信.
其中一些未来现在无声无息.我的日志中没有堆栈跟踪,或者在std {out,err}上没有堆栈跟踪.我已经尝试围绕期货所调用的fns中的代码
(try (do-stuff)
(catch Exception e
(log/error e))
Run Code Online (Sandbox Code Playgroud)
只是为了得到一些输出到我的日志,但是 - 令人惊讶! - 没有用.
我唯一的选择是启动另一个在循环中执行以下操作的线程吗?
(let [m (Thread/getAllStackTraces)]
(doseq [e (.entrySet m)]
(log/error (.toString (.getKey e)))
(doseq [s (.getValue e)]
(log/error " " (.toString s)))))
Run Code Online (Sandbox Code Playgroud)
这是否表明我根本不应该使用期货?我是否应该使用代理,即使不需要向这些代理发送任何消息?
行为与Java非常相似Future.在未来的块中,异常可能会被抛出并被捕获,并且行为与您期望的一样.如果未捕获异常,则无法Future在调用线程上重新抛出异常.只有ExecutionException当你真正得到它的价值时它才会这样做.这对应于Clojure中的deref.
让我们创建一个抛出某些东西的函数:
(defn die [] (throw (RuntimeException.)))
Run Code Online (Sandbox Code Playgroud)
如果我将来包装它,它可以正常工作:
user=> (def x (future (die)))
#'user/x
; Note: No exception here
user=> @x
RuntimeException user/die (NO_SOURCE_FILE:1)
; Bam! Exception thrown on deref, think of it as
; ExecutionException when getting failed future's value in Java
Run Code Online (Sandbox Code Playgroud)
所以你可以在deref上捕获这个异常:
user=> (def x (future (die)))
#'user/x
(try @x (catch Exception e (println "Caught ya")))
Caught ya
nil
Run Code Online (Sandbox Code Playgroud)
或者你可以在未来发现它:
user=> (def x
#_=> (future
#_=> (try (die)
#_=> (catch Exception e
#_=> (print "Caught ya!")
#_=> "Something"))))
#'user/x
Caught ya
user=> @x
"Something"
Run Code Online (Sandbox Code Playgroud)
注意在这种情况下如何在deref之前在后台线程上发生错误时立即打印"Caught ya".然后在deref上返回catch块将来返回的值.
最重要的是,底线是 - 它的工作方式与Java期货几乎相同.