Programming Clojure学习笔记——并发

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
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值