我第一次看Clojure core.async,正在经历Rich Hickey的精彩演讲:http://www.infoq.com/presentations/clojure-core-async
我对他在演讲结束时展示的例子有疑问:
根据Rich的说法,此示例主要尝试获取特定查询的Web,视频和图像结果。它为每个结果并行尝试两个不同的源,并为每个结果提取最快的结果。并且整个操作可能不会超过80毫秒,所以如果我们不能得到例如在80毫秒的图像结果,我们只是放弃。最快的' function创建并返回一个新的通道,并启动两个go过程来检索结果并将其放在通道上。然后我们只是从最快的'中取出第一个结果。通道并将其打到c通道上。
我的问题:这三个临时的,未命名的'最快的'我们取得他们的第一个结果后的渠道据推测,仍有一个停止过程试图将第二个结果放到通道上,但是没有人在听,所以它从未实际完成。而且由于频道从未与任何东西绑定,因此我们似乎无法再对它做任何事情。请问过程&渠道"实现"没有人再关心他们的结果并清理自己了吗?或者我们基本上只是"泄漏"这段代码中有三个渠道/进程?
答案 0 :(得分:3)
没有泄漏。
停放的go
附加到他们尝试执行操作的通道上,并且除此之外没有独立存在。如果其他代码对频道失去兴趣,则会停靠某个go
(注意。go
如果alt!
/ {{1 alts!
go
可以同时成为许多频道的推杆/接收者然后最终它将与那些频道一起进行GC。
唯一需要注意的是,为了成为GC,go
实际上必须首先停放。因此,任何<!
在不停车(>!
/ alt!
/ alts!
/ {{1}})的情况下继续在循环中完成任务的{{1}}实际上将永远存在。不过,很难写出这种代码。
答案 1 :(得分:3)
除了警告和例外,您可以在REPL上测试JVM上的垃圾收集。
例如:
(require '[clojure.core.async :as async])
=> nil
(def c (async/chan))
=> #'user/c
(def d (async/go-loop []
(when-let [v (async/<! c)]
(println v)
(recur))))
=> #'user/d
(async/>!! c :hi)
=> true
:hi ; core.async go block is working
(import java.lang.ref.WeakReference)
=> java.lang.ref.WeakReference ; hold a reference without preventing garbage collection
(def e (WeakReference. c))
=> #'user/e
(def f (WeakReference. d))
=> #'user/f
(.get e)
=> #object[...]
(.get f)
=> #object[...]
(def c nil)
=> #'user/c
(def d nil)
=> #'user/d
(println "We need to clear *1, *2 and *3 in the REPL.")
We need to clear *1, *2 and *3 in the REPL.
=> nil
(println *1 *2 *3)
nil #'user/d #'user/c
=> nil
(System/gc)
=> nil
(.get e)
=> nil
(.get f)
=> nil
刚刚发生了什么?我设置了一个go块并检查它是否正常工作。然后使用WeakReference来观察通信信道(c)和去块返回信道(d)。然后我删除了对c和d的所有引用(包括我的REPL创建的*1
,*2
和*3
),请求的垃圾回收,(幸运的是,System.gc Javadoc确实如此没有强有力的保证)然后观察到我的弱参考被清除了。
至少在这种情况下,一旦删除了对相关频道的引用,频道就会被垃圾收集(无论我是否关闭它们!)
答案 2 :(得分:1)
假设fastest
生成的频道只返回最快查询方法的结果,然后关闭。
如果产生了第二个结果,那么您的假设可能会导致fastest
过程被泄露。他们的结果从未消耗过。如果他们依赖所有结果来终止,他们就不会终止。
请注意,如果在t
子句中选择了频道alt!
,也会发生这种情况。
解决此问题的通常方法是使用c
关闭上一个go
块中的频道close!
。然后放弃对封闭通道的放置然后生产者可以终止。
问题也可以在fastest
的实施中解决。在fastest
中创建的流程本身可以通过alts!
和timeout
生成,并在生成的值未在一定时间内消耗时终止。
我认为Rich没有解决幻灯片中的问题,而是支持一个不太冗长的例子。