为什么Elixir消息传递时间与消息大小成正比?

时间:2016-02-01 16:46:47

标签: performance elixir

我发现在Elixir中传递消息所花费的时间与消息的大小成正比,而我预计它会相对恒定。由于数据结构是不可变的,因此运行时应该能够通过引用(在恒定时间内)在进程之间传递大型结构。考虑以下测试。

use Bitwise

defmodule PerfTask do
  def pack(s) do
    {millis, packed} = :timer.tc(fn -> Enum.to_list(s) end)
    IO.puts("packed in #{millis} millis")
    Task.async(fn -> packed end)    
  end

  def unpack(t) do
    {millis, unpacked} = :timer.tc(fn -> Task.await(t) end)
    IO.puts("unpacked in #{millis} millis")
    unpacked
  end

  def go(n) do
    IO.puts "n = #{n}"
    1..n |> pack |> unpack
  end
end

PerfTask.go(1 <<< 20)

列表中有2 ^ 20个元素,打印

n = 1048576
packed in 106481 millis
unpacked in 9916 millis

构建列表需要大约10倍的时间才能将其从Task中删除。 (请注意,列表是在任务开始之前构建的。所有任务都必须返回已经构建的列表。)

列表中有2 ^ 22个元素,打印

n = 4194304
packed in 397428 millis
unpacked in 38748 millis

该比率仍约为10:1。长4倍的列表在进程之间发送的时间长达4倍。我错过了什么?

$ iex
Erlang/OTP 18 [erts-7.2] [source] [64-bit] [smp:8:8] [async-threads:10] [kernel-poll:false]

Interactive Elixir (1.2.0) - press Ctrl+C to exit (type h() ENTER for help)

(我已经确认问题并非特定于Task模块,而是将其替换为具有类似结果的普通进程。)

1 个答案:

答案 0 :(得分:5)

根据@rvirding的这个answer,你的基本假设是有缺陷的。引用维尔丁先生:

  

。 。 。当前版本的Erlang基本上复制除了之外的所有内容   更大的二进制文件在较早的SMP之前,不可复制   但传递参考。虽然这导致了非常快速的消息传递   它在实现中产生了其他问题,主要是它   垃圾收集更加困难和复杂的实施。一世   认为今天传递参考和共享数据可以   导致过度锁定和同步,当然,   不是一件好事。

在Elixir的背景下,&#34;更大的二进制文件&#34;意味着非常长的字符串 - 大于64K。