Clojure:如何序列化函数并在以后重用它

时间:2017-04-21 14:36:50

标签: clojure

(defn my-func [opts]
  (assoc opts :something :else))

我希望能够做什么,将对函数的引用(可能通过#'my-func?)序列化为字符串,以便我可以在反序列化时使用args调用它。

这是如何运作的?

编辑 - 为什么这不重复

other question询问如何序列化函数体 - 整个函数代码。我不是问怎么做。我在问如何序列化参考。

想象一下所有运行相同jar的服务器集群,都连接到MQ。 MQ在fn-referencefn-args中为pub中的函数发布,并且集群中的服务器运行它并确认它。这就是我想要做的事情 - 不要传递函数体。

在某些方面,这就像在clojure中构建一个“无服务器”引擎。

2 个答案:

答案 0 :(得分:5)

正如评论中所建议的那样,如果您只是序列化该函数的关键字标签并存储/检索该标签,那么您就完成了。

如果您需要将函数从一个地方传送到另一个地方,您基本上需要将函数源代码作为字符串发送,然后在另一端通过eval进行编译。这是Datomic在数据库函数存储在数据库中时所执行的操作,并且由Datomic自动运行以对数据库进行任何新的添加/更改(例如,这些可以执行自动数据验证)。见:

the book Clojure in Action (1st Edition)中使用类似的技术用于使用RabbitMQ的分布式计算引擎示例。

答案 1 :(得分:5)

奇怪的是,序列化var identity的提交昨天只是添加到Clojure:https://github.com/clojure/clojure/commit/a26dfc1390c53ca10dba750b8d5e6b93e846c067

从最新的主快照版本开始,您可以序列化Var(如#'clojure.core/conj)并在另一个JVM上反序列化,并且可以访问相同的加载代码,然后调用它。

(import [java.io File FileOutputStream FileInputStream ObjectOutputStream ObjectInputStream])

(defn write-obj [o f]
  (let [oos (ObjectOutputStream. (FileOutputStream. (File. f)))]
    (.writeObject oos o)
    (.close oos)))

(defn read-obj [f]
  (let [ois (ObjectInputStream. (FileInputStream. (File. f)))
        o (.readObject ois)]
    (.close ois)
    o))

;; in one JVM
(write-obj #'clojure.core/conj "var.ser")

;; in another JVM
(read-obj "var.ser")