gpt4 book ai didi

elixir - 为什么这个 Elixir 代码这么慢?

转载 作者:行者123 更新时间:2023-12-04 18:04:59 25 4
gpt4 key购买 nike

我目前对学习 Elixir 非常感兴趣,我学习一门新语言的典型方法是用它构建简单的程序。

所以我决定编写一个(非常简单的)类似 grep 的程序(或模块),如下所示:

defmodule LineMatch do
def file(s, path) do
case File.open(path, [:read]) do
{:ok, fd} -> match s, fd
{_, error} -> IO.puts "#{:file.format_error error}"
end
end
defp match(s, fd) do
case IO.read fd, :line do
{:error, error} -> IO.puts("oh noez! Error: #{error}")
line -> match(s, line, fd)
end
end
defp match(s, line, fd) when line !== :eof do
if String.contains?(line, s) do
IO.write line
end
match(s, IO.read(fd, :line), fd)
end
defp match(_, _line, _) when _line === :eof do
end
end

这很可能不是最优雅的方法,而且我对函数式编程也很陌生,所以我没想到它会 super 快。但它不仅不快,它实际上是 super 慢 .太慢了,我可能犯了一些非常明显的错误。

谁能告诉我,它是什么以及如何使它变得更好?

我通常使用单独的 .exs 文件来测试代码,例如
case System.argv do
[searchTerm, path] -> LineMatch.file(searchTerm, path)
_ -> IO.puts "Usage: lineMatch searchTerm path"
end

最佳答案

您可以通过做两件事来获得良好的性能,而不是像 lad2025 的答案那样读取整个文件。首先,使用 IO.binstream构建文件行的流,但作为原始二进制文件(用于性能)。使用 IO.stream读取为 UTF-8,因此在读取文件时会产生额外的转换成本。如果您需要 UTF-8 转换,那么它会很慢。此外,使用 Stream.filter/2 应用过滤和映射操作和 Stream.map/2函数可防止您多次迭代行。

defmodule Grepper do
def grep(path, str) do
case File.open(path) do
{:error, reason} -> IO.puts "Error grepping #{path}: #{reason}"
{:ok, file} ->
IO.binstream(file, :line)
|> Stream.filter(&(String.contains?(&1, str)))
|> Stream.map(&(IO.puts(IO.ANSI.green <> &1 <> IO.ANSI.reset)))
|> Stream.run
end
end
end

我怀疑您的代码的最大问题是 UTF-8 转换,但可能是通过调用 IO.read 逐行从文件中“拉取” , 而不是使用 IO.stream|binstream 将行“推送”到您的过滤/打印操作中,你在那里产生了一些额外的费用。我必须查看 Elixir 的源代码才能确定,但​​是上面的代码在我的机器上性能非常好(我正在从 Olson 时区数据库中搜索一个 143kb 的文件,不知道它将如何在非常大的文件上执行我手边没有一个好的示例文件)。

关于elixir - 为什么这个 Elixir 代码这么慢?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/31395097/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com