【问题标题】:Difference between spawn/1 and spawn/3spawn/1 和 spawn/3 的区别
【发布时间】:2016-12-29 14:18:18
【问题描述】:

我相信我在某处读到过在热重载方面使用spawn/1spawn/3 之间存在差异,但我找不到有关该主题的任何完整信息。所以我想知道是否真的有区别,如果有,那是什么?一些例子会很棒。谢谢。

【问题讨论】:

    标签: elixir


    【解决方案1】:

    两者的区别在于spawn/1进行本地函数调用,而spawn/3进行“完全限定”函数调用。

    当您加载模块的新版本时,旧版本仍然保留,并且在旧版本中执行的任何进程都会继续这样做。例外情况是进程执行“完全限定”函数调用,包括模块名称:在这种情况下,始终使用最新版本的代码。

    例如,使用这个模块:

    defmodule Foo do
    
      def start_loop do
        spawn(fn -> loop end)
      end
    
      def loop do
        receive do
          :foo ->
            spawn &print_foo/0
            loop
          :reload ->
            Foo.loop
        end
      end
    
      def print_foo do
        IO.puts "foo 1"
      end
    end
    

    我们可以启动一个进程,每次我们向它发送:foo,它都会生成另一个打印foo 1的进程:

    iex(1)> c("foo.ex")
    [Foo]
    iex(2)> p = Foo.start_loop
    #PID<0.68.0>
    iex(3)> send p, :foo
    foo 1
    :foo
    iex(4)> send p, :foo
    foo 1
    :foo
    

    现在,如果我们将模块修改为打印foo 2,然后重新编译并重新加载它,则不会立即更改:

    iex(5)> c("foo.ex")       
    warning: redefining module Foo (current version loaded from Elixir.Foo.beam)
      foo.ex:1
    
    [Foo]
    iex(6)> send p, :foo
    foo 1
    :foo
    

    只有当我们通过对模块进行完全限定的调用来告诉进程“重新加载”时,我们才能获得新版本:

    iex(7)> send p, :reload
    :reload
    iex(8)> send p, :foo   
    foo 2
    :foo
    

    当然,如果您将spawn/1 与只进行完全限定调用的函数一起使用,则差异就消失了:

    spawn(fn -> Foo.print_foo end)
    

    【讨论】:

      猜你喜欢
      • 2022-06-19
      • 2010-10-07
      • 1970-01-01
      • 2013-07-25
      • 1970-01-01
      • 2014-11-13
      • 1970-01-01
      • 2017-01-23
      • 2011-08-06
      相关资源
      最近更新 更多