【问题标题】:Erlang copying of dataErlang 复制数据
【发布时间】:2014-04-19 13:47:15
【问题描述】:

在> Chapter 14 Programming with sockets 一书中,

Joe 给了我们两个版本的 receive_data(Socket, SoFar):

receive_data(Socket, SoFar) ->
    receive
        {tcp,Socket,Bin} ->
            receive_data(Socket, [Bin|SoFar]);
        {tcp_closed,Socket} ->
            list_to_binary(reverse(SoFar))
    end

receive_data(Socket, SoFar) ->
    receive
        {tcp,Socket,Bin} ->
            receive_data(Socket, list_to_binary([SoFar,Bin]));
        {tcp_closed,Socket} ->
            SoFar
    end.

然后乔说:

在后一个版本中,我们不断将新的二进制文件附加到 缓冲区的末尾,这涉及到大量的数据复制。

但我仍然不太清楚 [Bin|SoFar] 和 list_to_binary([SoFar,Bin]) 之间的区别。

Joe 所说的“大量数据复制”是什么意思?

list_to_binary 还是 [SoFar, Bin] 哪个函数会处理大量数据?

【问题讨论】:

    标签: list sockets erlang


    【解决方案1】:

    我对深 erlang 内部原理一无所知,但这是我的看法:

    list_to_binary([SoFar,Bin]) 在每次调用时都会创建一个新的二进制文件:编译器无法对其进行优化。所有数据都必须复制并组装到新分配的内存空间中。

    [Bin|SoFar] 只是将一个元素添加到列表中(which is good),它不涉及复制数据,只有指针移动。这是构建列表的正确方法,而不是不断增长的列表的大量副本。

    【讨论】:

      【解决方案2】:

      它来自于列表和二进制文件的区别

      列表要么是一个空列表,要么是由一个元素(头部)构成的结构,要么是一个指向列表其余部分(尾部)的“链接”。它是 语法 [H|T] 的含义。在 C 代码中,它可以用一对指针来实现,第一个指针指向元素或 nil(空列表), 第二个指向尾部:另外几个指针。 - 我没有检查 erlang 库中的实现。

      这意味着当您想要在接收到新数据块时创建一个新列表时,使用列表的解决方案只是创建这个新列表的头部 其中包含对新接收到的数据 (Bin) 的引用和对先前接收到的数据 (SoFar) [Bin|SoFar] 的引用。这是可能的,因为所有变量都是不可变的。

      二进制文件没有内部结构,因此如果您想使用 list_to_binary([Bin,SoFar]) 将接收到的单个二进制文件(第二种解决方案)中的全部数据加肥,编译器会分配一个新的内存空间并将所有数据复制到它。 不可变数据的相同原理阻止它优化执行。

      【讨论】:

        猜你喜欢
        • 2012-10-06
        • 2016-10-28
        • 1970-01-01
        • 2015-09-10
        • 1970-01-01
        • 2011-07-02
        • 2017-07-09
        • 2012-01-10
        • 2014-09-09
        相关资源
        最近更新 更多