用长生不老药将Enum转换为Flow

时间:2019-06-12 08:57:47

标签: elixir

我有200万个数据文件要处理。 以下代码需要2个小时才能完成。

out_file = "./output.tsv"
result = "./input.tsv"
         |> File.stream!
         |> CSV.decode(separator: ?\t, headers: headers)
         |> Enum.map(&(elem(&1, 1)))
         |> Enum.group_by(&{&1.id, &1.name})
         |> Enum.map(&(format_data(&1)))
File.write(out_file, result)

为了获得更高的性能,我使用了Flow,然后编写了以下代码。 好像是Enum,所以我只添加了Flow.from_enumerable,然后将Enum重新写入了Flow

out_file = "./output.tsv"
result = "./input.tsv"
         |> File.stream!
         |> CSV.decode(separator: ?\t, headers: headers)
         |> Flow.from_enumerable(stages: 4)
         |> Flow.map(&(elem(&1, 1)))
         |> Flow.group_by(&{&1.id, &1.name})
         |> Flow.map(&(format_data(&1)))
File.write(out_file, result)

它不起作用。我认为使用Flow这样的方式不正确。 请让我知道您的建议,以正确使用Flow

1 个答案:

答案 0 :(得分:1)

Flow主文档页面上最上面的示例显示,您必须终止Flow以及Stream并使用类似Enum.to_list()的名称。

在您的第一个摘录中,终止发生在第一次调用Enum.map/2Stream.map/2时,并且family将用于流处理,File.stream!/1的作用与{{1} },因为您立即将其终止。)

此外,NimbleCSV由Elixir核心团队明确创建,用于流处理CSV。无论如何,下面的方法可能会起作用:

Fire.read/1

更好的方法是:

result =
  "./input.tsv"
  |> File.stream!
  # here the stream is terminated
  |> CSV.decode(separator: ?\t, headers: headers)
  |> Flow.from_enumerable(stages: 4)
  |> Flow.map(&(elem(&1, 1)))
  |> Flow.group_by(&{&1.id, &1.name})
  |> Flow.map(&(format_data(&1)))
  # ⇓ THIS IS IMPORTANT
  |> Enum.to_list()