我正在尝试使用以下代码逐行散列文件(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()
Run Code Online (Sandbox Code Playgroud)
根据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]
Run Code Online (Sandbox Code Playgroud)
time在大约2.3秒内运行(仍然按照).
我将在哪里提高我的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()
Run Code Online (Sandbox Code Playgroud)
但它产生的结果甚至更差,大约11秒以上,为什么会这样?
需要考虑的一件事是,使用时间来记录 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 )
Run Code Online (Sandbox Code Playgroud)
对于 16mb 文件。在管道中使用 Stream 几乎总是以速度换取内存使用。由于数据在 Elixir 中是不可变的,因此大型列表的开销通常比您最初预期的要少。
您基于任务的代码不会有太大帮助,因为我怀疑大部分时间都花在对这两行中的行进行分块上。
File.stream!(path)
|> Stream.chunk(chunk_size) # with chunk_size being (nb_of_lines_in_file / 10)
Run Code Online (Sandbox Code Playgroud)
那会非常慢。您可能会发现有用的另一个代码示例。 https://github.com/dimroc/etl-language-comparison/tree/master/elixir
您可以使用很多技巧在 Elixir 中实现快速文件处理。您通常可以将原始版本的速度提高File.stream!多个数量级。
| 归档时间: |
|
| 查看次数: |
844 次 |
| 最近记录: |