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