目前没有简单的方法在确保所有已提交的操作都已完成且没有新的操作发送的情况下关闭代理。
这里有一个简单的方法:
(shutdown-agents)
但这种方法有两个问题
1) 它将丢弃所有已提交但尚未启动的操作。
2) 它不会阻止向代理发送进一步的操作(不会抛出显式的错误,只是静默忽略)。
以下是一个证明:
`
(def my-agent (agent 1))
(defn sleep-and-inc [number]
(Thread/sleep 3000)
(println "操作编号" number "完成")
(inc number))
(println "发送2次")
(send-off my-agent sleep-and-inc)
(send-off my-agent sleep-and-inc)
(println "发送完成")
(shutdown-agents)
(println "请求关闭")
(println "发送第三次")
(send-off my-agent sleep-and-inc)
(println "发送完成")
`
以下是输出结果:
发送2次 发送完成 请求关闭 发送第三次 发送完成 操作编号1 完成
如你所见——第2次操作被丢弃,第3次操作被忽略了。
顺便说一下,shutdown-agents的文档字符串具有误导性(不明确)
"...正在运行的操作将继续完成,但不会接受新的操作..."
1) 它没有提到已提交的操作
2) "不会接受新的操作"听起来应该会有错误,但它是静默忽略的。
因此,更好的文档字符串应该是 "...正在运行的操作将继续完成,等待的操作将被丢弃,新的操作将被忽略..."
在Java中类似的方法工作得很好
`
ExecutorService executor = Executors.newSingleThreadExecutor();
executor.submit(new Runnable() {
@Override
public void run() {
try {
Thread.sleep(3000);
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
System.out.println("Action 1 complete");
}
});
executor.submit(new Runnable() {
@Override
public void run() {
try {
Thread.sleep(3000);
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
System.out.println("Action 2 complete");
}
});
executor.shutdown();
System.out.println("Shutdown requested");
// //将抛出RejectedExecutionException
// executor.submit(new Runnable() {
// @Override
// public void run() {
// try {
// Thread.sleep(3000);
// } catch (InterruptedException e) {
// throw new RuntimeException(e);
// }
// System.out.println("操作3完成");
// }
// });
`
输出
请求关闭 操作1完成 操作2完成
当我说是“工作得很好”时,我是指
1) 它将完成所有等待的任务(不仅仅是正在运行的)
2) 在调用"shutdown"后,将抛出错误处理新的任务。
所以,回到Clojure——我们目前只剩下一个这样的惯用法(并非微不足道!)
(await my-agent) (shutdown-agents)
这不是一个简单直接的习惯用法,因为
1) 你需要跟踪系统中的所有代理。如果你在使用使用代理的第三方代码,那就变得几乎不可能了。
2) 即便在等待或关闭过程中发送其他动作,也不会抛出异常。
建议
(受Java启发)
1) 创建一个名为"shutdown-agents-gracefully"的新函数,该函数将执行两个额外的操作
1.1) 将代理系统置于"关闭中"状态
1.2) 完成因运行和等待而未完成的活动
2) 修改"send"和"send-off"函数,使其在代理系统处于"关闭中"状态时抛出错误。
3) 修复"shutdown-agents"函数的文档字符串(见上文)
在验证此jira工单后,我将开始开发补丁。