6.4 使用Agents进行异步更新
类似引用,可以使用代理(agent)包装初始状态。
(agent initial-state)
如创建counter代理包装初始计数0:
(def counter (agent 0))
可以send一个函数到agent修改agent的状态,该函数不会立即执行,而是存放到线程池的send队列中,稍后执行:
(send agent update-fn & args)
如counter加一:
(send counter inc)
同样地,可以通过deref和@查看agent的当前值:
@counter #返回 1
如果你想确保send到agent的函数被执行,可以调用await或await-for:
(await & agents)
(await-for timeout-millis & agents)
它们将阻塞线程,直到agent完成函数执行。 await-for等待超时后将返回nil,而await就一直等待直到agent完成函数执行,因此要谨慎使用。
代理验证和错误处理
与refs类似,agent创建时也可以指定验证函数:
(agent initial-state options*)
这里选项options包括
(1) :validator validate-fn
(2) :meta metadata-map
可以通过agent-errors获取agent执行过程中的异常,如:
(agent-errors counter)
一旦agent有错误,所有后续的查询都将返回错误,可以通过clear-agent-errors是agent变得可用:
(clear-agent-errors counter)
在事务中使用代理Agent
如果在事务中send一个操作到代理agent,则当且仅当事务成功时,该操作仅被执行一次。
举例说明:
定义聊天信息备份代理
(def backup-agent (agent "output/message-backup.clj"))
重新改写添加消息函数
(use '[clojure.contrib.duck-streams :only (split)])
(defn add-message-with-backup [msg]
(dosync
(let [snapshot (commute messages conj msg)]
(send-off backup-agent (fn [filename](spit filename snapshot) filename))
snapshot)))
这里使用了send-off代替send,send-off是send的一个变体将阻塞线程,就像写文件操作一样。
统一更新模型
引用(refs),原子(atoms)和代理(agents)都是通过应用函数到它们之前的状态来更新它们的状态,这种处理共享状态的统一模型是Clojure的一种核心概念。这种统一模型和各种辅助函数如下表所示:
Update Mechanism Ref Function Atom Function Agent Function
Function application alter swap! send-off
Function(commutative) commute N/A N/A
Function(nonbocking) N/A N/A send
Simple setter ref-set reset! N/A
类似引用,可以使用代理(agent)包装初始状态。
(agent initial-state)
如创建counter代理包装初始计数0:
(def counter (agent 0))
可以send一个函数到agent修改agent的状态,该函数不会立即执行,而是存放到线程池的send队列中,稍后执行:
(send agent update-fn & args)
如counter加一:
(send counter inc)
同样地,可以通过deref和@查看agent的当前值:
@counter #返回 1
如果你想确保send到agent的函数被执行,可以调用await或await-for:
(await & agents)
(await-for timeout-millis & agents)
它们将阻塞线程,直到agent完成函数执行。 await-for等待超时后将返回nil,而await就一直等待直到agent完成函数执行,因此要谨慎使用。
代理验证和错误处理
与refs类似,agent创建时也可以指定验证函数:
(agent initial-state options*)
这里选项options包括
(1) :validator validate-fn
(2) :meta metadata-map
可以通过agent-errors获取agent执行过程中的异常,如:
(agent-errors counter)
一旦agent有错误,所有后续的查询都将返回错误,可以通过clear-agent-errors是agent变得可用:
(clear-agent-errors counter)
在事务中使用代理Agent
如果在事务中send一个操作到代理agent,则当且仅当事务成功时,该操作仅被执行一次。
举例说明:
定义聊天信息备份代理
(def backup-agent (agent "output/message-backup.clj"))
重新改写添加消息函数
(use '[clojure.contrib.duck-streams :only (split)])
(defn add-message-with-backup [msg]
(dosync
(let [snapshot (commute messages conj msg)]
(send-off backup-agent (fn [filename](spit filename snapshot) filename))
snapshot)))
这里使用了send-off代替send,send-off是send的一个变体将阻塞线程,就像写文件操作一样。
统一更新模型
引用(refs),原子(atoms)和代理(agents)都是通过应用函数到它们之前的状态来更新它们的状态,这种处理共享状态的统一模型是Clojure的一种核心概念。这种统一模型和各种辅助函数如下表所示:
Update Mechanism Ref Function Atom Function Agent Function
Function application alter swap! send-off
Function(commutative) commute N/A N/A
Function(nonbocking) N/A N/A send
Simple setter ref-set reset! N/A