大文件和散列 - 性能问题

时间:2015-12-18 12:39:18

标签: elixir

我尝试使用以下代码逐行散列文件(16 MB):

 def hash(data, protocol) do
   :crypto.hash(protocol, data)
   |> Base.encode16()
 end

 File.stream!(path)
 |> Stream.map(&hash(&1, :md5) <> "h")
 |> Enum.to_list()
 |> hd()
 |> IO.puts()

根据time命令,这需要10到12秒,这似乎是一个巨大的数字,我考虑使用以下Python代码:

import md5

with open('a', 'r') as f:
    content = f.readlines()
    l = []
    for _, val in enumerate(content):
        m = md5.new()
        m.update(val)
        l.append(m.hexdigest() + "h")

    print l[0]

在大约2.3秒内运行(仍然根据time)。

我将在哪里提高我的Elixir代码的性能?我试图将初始流拆分为10个块,并为每个块启动异步任务:

File.stream!(path)
|> Stream.chunk(chunk_size) # with chunk_size being (nb_of_lines_in_file / 10)
|> Enum.map(fn chunk -> Task.async(fn -> Enum.map(chunk, &hash(&1, :md5) <> "h") end) end)
|> Enum.flat_map(&Task.await/1)
|> hd()
|> IO.puts()

但它会产生甚至更差的结果,大约11秒以上,这是为什么?

1 个答案:

答案 0 :(得分:2)

要考虑的一件事是,使用时间来记录Elixir代码的性能总是要考虑在内 BEAM虚拟机的启动时间。取决于你的 申请,将其包含在任何内容中可能有意义也可能没有意义 比较其他语言的基准。如果你只是想 最大化Elixir代码的性能,最好使用基准测试 像Benchfella这样的工具甚至只是:来自erlang的timer.tc。

https://hex.pm/packages/benchfella

我的猜测是你的性能问题都与I / O有关。 File.stream!对大型文件的行处理效率不高。

我写了一篇关于哈希整个文件的类似问题的博文。

http://www.cursingthedarkness.com/2015/06/micro-benchmarking-in-elixir-using.html

这里有关于快速基于线路处理的幻灯片。

http://bbense.github.io/beatwc/

我认为如果你把整个文件淹没在你身上会得到更好的表现。我会毫不犹豫地使用

File.stream!(path) |> Enum.map(fn(line) -> hash(line, :md5) <> "h" end )

获取16mb文件。在管道中使用Stream几乎总是以内存的速度进行交换。由于数据在Elixir中是不可变的,因此大型列表的开销通常比您最初预期的要少。

基于任务的代码不会有太大的帮助,因为我怀疑大多数代码 时间用于分块这两行中的行。

File.stream!(path)
|> Stream.chunk(chunk_size) # with chunk_size being (nb_of_lines_in_file / 10)

那会很慢。您可能觉得有用的另一个代码示例。 https://github.com/dimroc/etl-language-comparison/tree/master/elixir

您可以使用许多技巧在Elixir中快速处理文件。您通常可以将原始File.stream!版本的速度提高多个数量级。