erlang可以重用进程ID吗?如果是这样,如何确定正确性?

Hos*_*een 3 erlang

(1)进程死后,是否有可能将其pid重新分配给由spawn()?创建的另一个进程?

(2)如果是,那么通信安全如何?例如,向Pid邮件的发件人发送回复.如果发件人已崩溃,我们怎么知道这Pid不属于另一个进程呢?

(3) pid重用有什么保证?例如,在重用pid之前是否有最小间隔?

(4)通常采取哪些措施来防止因重复使用pid而导致的错误?它被忽略了吗?

zxq*_*xq9 6

很多问题......

  1. 是.PID可以重复使用.
  2. 通信是"安全的(ish)",因为以任何一致性命中重用PID的可能性极小.击球网络和硬件错误是深刻地比这更容易.我们设计了面向稳健性的程序,其中包括以可接受错误消息和/或过程自发死亡的方式编程(这种死亡的成本构建在重启周期中).
  3. 对它的保证至少基于我对主要EVM实现(例如HiPE不确定)的经验,因为整数赋值空间非常大并且发送消息的速度比整数循环快得多.大多数情况下.
  4. 避免基于PID重用的怪异的关键是将它与其他东西结合起来,这也是典型使用范围内的唯一值 - 并且通常采用Erlang引用的形式.

一方面没有详尽无遗,另一方面又过于迂回,我们考虑一个实际的例子:OTP功能gen_server:call/2,3.

当您使用gen_server:call/2,3gen_server模块时,生成一个组合的消息标记,{self(), make_ref()}除了监视正在发送消息的进程外,还看起来像.发送过程保证至少如果它正在调用的进程在发送回复之前死亡,将接收监视器退出消息而不是响应,并且死亡进程的PID将与它刚刚调用的PID匹配.被接收消息的接收处理将被接收发送方的PID 被保证是本地唯一一个Erlang参考(至少对于相当长的时间-相信独特的空间中的某处十亿) .当它发送响应时,接收过程也必须知道该引用,并且由最初用于发送的PID寻址.

这是可能的(虽然非常不可能),其发送过程中可能已经死了,一个新的进程可能已经重生具有相同PID,但它是非常接近不可能用相同的PID催生另一个进程,并会阻止gen_server:call/2,3恰好具有与旧的死调用相同的内部运行时引用的消息.

除了这种几乎不可能之外,让我们考虑一个世界,这个世界真的发生了奇怪的事情,所有的保护措施都失败了......

(大约2^64 * 2^64 * chance_of_failure_on_this_tiny_scale())

发送过程会得到一个奇怪的响应消息,几乎肯定会失败一个断言匹配并在下一行死掉,并在已知状态下重启.两次发生同样问题的可能性可能低于接下来几分钟内质子衰减的几率.

这是"正确性"吗?没有.在大规模并发系统中没有可证明的正确性.这就像试图"证明"代表全人类的单一方程式.大多数Erlang系统本质上都是混乱的,因此通常无法证明系统.您可以证明的是,单个纯函数是正确的,并且副作用过程在其生命周期中可能调用的所有函数都具有明确的终止条件,包括崩溃对不稳定的数据.最后一部分是Erlang如何实现如系统的强大稳健性(良好的编码实践,遵守功能原则以及使用Dialyzer的强大文化也有很大帮助).

所以......"正确性"......尽可能多地证明功能.这是一件好事,为什么我们有像PropER和QuickCheck这样的工具.作为一套通用指南,请尽力写下:

  • 尽可能经常保持纯粹的功能.将副作用代码尽可能地与纯代码隔离,纯代码除了计算和返回值之外什么都不做.
  • 可证明可崩溃的流程.让每一行都有一个=.这就是为什么Erlang =是一体化的赋值,断言和统一的原因.
  • 具有可证明状态的协议.例如,您不能以阻塞的方式相互调用两个相同的进程,而不会出现死锁的风险.这是并发系统的基本限制.CAP定理是另一个定理.根据这些约束设计您的系统(这是奇怪的解放)并有意识地选择您的权衡.

除非你在学术界(这个功能可能会在下面调用一个巨大的世界,所以这并不是一个很大的限制),以比功能更大的比例进行校对是一个愚蠢的错误.针对不可能或锁定条件的校对协议也是可能的,如果你有时间,那就去吧(否则做我们其他人做的事情,并坚持超时和返工过去实际上超时的代码) - 这不应该是经常发生的事情).

所有这一切...... Steve-O几乎肯定会在数据中心的数据线上绊倒并在接下来的两年内将群集拆分多次,而不是任何人看到PID环绕导致实际的冲突.下一个十年.