我需要在 Erlang 中序列化一个函数,将其发送到另一个笔记,反序列化并在那里执行它。我遇到的问题是文件。如果函数从不在第二个节点中的文件读取,我会收到错误消息。有没有办法区分 Erlang 中可序列化和不可序列化的结构?因此,如果一个函数使用文件或 pid,那么它无法序列化?
谢谢
我需要在 Erlang 中序列化一个函数,将其发送到另一个笔记,反序列化并在那里执行它。我遇到的问题是文件。如果函数从不在第二个节点中的文件读取,我会收到错误消息。有没有办法区分 Erlang 中可序列化和不可序列化的结构?因此,如果一个函数使用文件或 pid,那么它无法序列化?
谢谢
在某些情况下,这个函数甚至不会被执行,或者会以完全错误的方式执行。
Erlang 中的每个函数,即使是匿名函数,都属于某个模块,准确地说,是在它内部构建的那个模块中。如果这个函数已经内置在 REPL 中,它会绑定到 erl_eval 模块,这更加危险(我会进一步解释,为什么)。
比如说,你启动了两个节点,其中一个有一个名为“foo”的模块,一个没有加载这样的模块(并且无法加载它)。如果你在模块 'foo' 中构造一个 lambda,将它发送到第二个节点并尝试调用它,你将失败并返回 {error, undef}。
可能还有另一个有趣的问题。尝试制作两个版本的模块'foo',在每个版本中实现一个'bar'函数并在其中实现一个lambda(但lambdas会有所不同)。尝试调用已发送的 lambda 时,您会遇到另一个错误。
我认为,将 lambdas 发送到不同的节点可能还有其他棘手的部分,但相信我,这已经很多了。
即使有一种方法可以从 lambda 中捕获封闭变量(如果您查看二进制化的 lambda,其中使用的所有外部变量都从第 2 个字节开始列出),但它们并不是唯一的来源潜在的 pid 或端口。
考虑一个简单的例子:你self()
在你的 lambda 中调用一个函数。它会返回什么?对,一个pid。好的,我们大概可以解析二进制文件并捕获这个函数调用,以及十几个其他内置函数。但是当你调用一些外部函数时你会怎么做呢?ets:lookup(sometable, somekey)
? some_module:some_function_that_returns_god_knows_what()
? 你不知道他们会返回什么。
处理文件时,始终发送文件名,而不是描述符。如果您需要文件的位置或其他内容,请同时发送。文件描述符不应该在打开它们的进程之外为人所知。
正如我所提到的,尽一切努力避免将 lambdas 发送到其他节点。很难说如何避免这种情况,因为我不知道你的确切任务。也许,您可以发送要执行的函数列表,例如:
[{module1, parse_query},
{module1, dispatch_parsed_query},
{module2, validate_response},
{module2, serialize_query}]
并通过此函数序列传递参数(确保所有模块都存在于任何地方)。也许,您实际上可以坚持使用一些将经常更改并部署在整个集群上的模块。也许,您可能想要切换到 JS/Lua 并使用外部启动的端口(Riak 正在使用 spidermonkey 来处理 JS 编写的 lambdas 以用于 Map/Reduce 请求)。最后,您实际上可以获取模块的目标代码,将其发送到另一个节点并在那里加载。请记住,它也不安全。您可以中断一些正在运行的进程,丢失一些构造的 lambda,等等。