【问题标题】:Why is agent returning nil and not waiting in clojure?为什么代理返回 nil 而不是在 clojure 中等待?
【发布时间】:2016-10-16 07:02:30
【问题描述】:
(def file (agent nil))

(defn read-file []
    (if (= @file nil)
        (do
            (println "read-file")
            (send-off file #(slurp %2) (io/resource "file.txt")))
        nil)
    @file)

如果我第一次调用read-file,它会返回nil。对于所有后续调用,它会返回文件内容。这是为什么?当我使用atom 时,它可以正常工作。还有为什么#(slurp %2) 需要第二个参数?当我只提供% 时它不起作用?我收到以下错误:

clojure.lang.ArityException: Wrong number of args (2) passed to: core/read-file/fn--3603

【问题讨论】:

    标签: concurrency clojure


    【解决方案1】:

    代理上的 Deref 提供当前状态的快照。代理使用nil 进行初始化,因此在初始状态取消引用它会返回nil。

    如果您想等到结果可用,您可以在代理上使用future 或致电await。如果只有一个操作产生结果,future 将是我的首选。在这个特定的例子中,我只写(slurp (io/resource "file.txt")),但没有任何并发​​构造。

    【讨论】:

    • 谢谢,在 deref 工作之前添加await。你知道为什么#(slurp %2) 需要%2 而不是% 吗?如果我要使用future 意味着send-off 应该被包装在未来对吧?
    • 我无法让它与未来一起工作。它给出了相同的行为。你有什么例子吗?
    • 顺便说一句,这段代码对我来说没有意义。为什么读取文件不只是(slurp (io/resource "file.txt"))?而不是使用agent?您需要%2,因为匿名函数的第一个参数是代理的状态。
    • 我想缓存结果。使用future 不起作用。
    • @kadaj 然后我会使用原子。 (def content (atom (slurp (io/resource "file.txt")))
    【解决方案2】:

    代理是错误的并发原语。它具有您不想要的所有特征,并且没有您想要的特征。相反,由于您要缓存的内容是单个昂贵的操作,因此请使用延迟:

    (let [file (delay (slurp (io/resource "file.txt")))]
      (defn read-file []
        @file))
    

    【讨论】:

    • 我不确定这是否是他想要的。延迟将计算推迟到未来,直到你意识到它。例如,这需要 20 秒:(time (do (def d (delay (Thread/sleep 10000) 1)) (Thread/sleep 10000) @d))。此外,还不清楚 kadaj 的价格是否昂贵。他可能只是想读取一个文本文件并将内容存储在某个地方。至少,这是我从答案下方的对话中理解的。
    • @MichielBorkent,在这种情况下,他可以使用promise。无论如何,代理显然是错误的抽象。
    猜你喜欢
    • 2017-11-25
    • 1970-01-01
    • 2022-01-21
    • 1970-01-01
    • 2011-08-14
    • 2011-08-28
    • 1970-01-01
    • 1970-01-01
    • 2015-03-31
    相关资源
    最近更新 更多