理解流程,让我变得缓慢

时间:2017-09-28 02:57:40

标签: elixir

我有一个很大的map,我使用理解创建组合,然后过滤组合......

for a <- data[:a],
    b <- data[:b],
    c <- data[:c],
    reducer(a ++ b ++ c) <= @limit do
      a ++ b ++ c
    end

据我所知,这不是并行完成的,只使用一个核心(?)

所以,我想在此添加Flow,以便在创建组合时,可以并行过滤它们。

以下是一个由3个功能组成的模块:

  • CompFlow.no_flow:没有流量,只是使用理解
  • CompFlow.enum_flow:使用理解创建Enum,然后使用流程过滤
  • CompFlow.stream_flow:将组合创建为Stream,并在创建流时过滤它们......我想

我认为这些功能中的每一个都应该比下一个功能更快,但事实恰恰相反...... no_flowenum_flow快一个数量级比stream_flow快几个数量级。

我显然对如何申请流量有一个根本的误解...有人可以解释我在这里做错了什么,如果我想做什么(加快理解力)是可能的?

完整模块:

defmodule CompFlow do
  @moduledoc false

  require Logger

  @limit 9
  @data %{
    :a => [
      [{1, "a"}, {2, "b"}],
      [{5, "w"}, {4, "x"}],
      [{1, "y"}, {3, "z"}]
    ],
    :b => [
      [{1, "a"}, {2, "b"}],
      [{3, "i"}, {3, "j"}],
      [{2, "e"}, {1, "f"}]
    ],
    :c => [
      [{1, "g"}],
      [{3, "s"}],
      [{3, "v"}]
    ]
  }

  @doc """
  Create and filter combos with a comprehension.
  """
  def no_flow(data \\ @data) do
    Logger.info "Starting to create combos"
    combos = for a <- data[:a],
                 b <- data[:b],
                 c <- data[:c],
                 reducer(a ++ b ++ c) <= @limit do
                   a ++ b ++ c
                 end
    Logger.info "Combos created"
  end

  @doc """
  Create all combos, then filter the resulting
  `Emun` using a `Flow`.
  """
  def enum_flow(data \\ @data) do
    Logger.info "Starting to create combos"
    combos = for a <- data[:a],
                 b <- data[:b],
                 c <- data[:c] do
                   a ++ b ++ c
                 end

    filtered_combos = combos
    |> Flow.from_enumerable()
    |> Flow.partition()
    |> Flow.reduce(fn -> [] end,
                   fn x, acc ->
                     if reducer(x) <= @limit do
                       acc ++ [x]
                     else
                       acc
                     end
                   end)
    |> Enum.to_list()
    Logger.info "Combos created"
  end

  @doc """
  Create combos and filter the `Stream` using
  a `Flow`.
  """
  def stream_flow(data \\ @data) do
    Logger.info "Starting to create combos"
    combos = for a <- data[:a],
                 b <- data[:b],
                 c <- data[:c] do
                   [a ++ b ++ c]
                   |> Flow.from_enumerable()
                   |> Flow.partition()
                   |> Flow.reduce(fn -> [] end,
                                  fn x, acc ->
                                    if reducer(x) <= @limit do
                                      acc ++ x
                                    else
                                      acc
                                    end
                                  end)
                   |> Enum.to_list()
                 end
    filtered_combos = Enum.filter(combos, &(length(&1) > 0))
    Logger.info "Combos created"
  end

  defp reducer(enum) do
    Enum.reduce(enum, 0, fn(x, acc) -> elem(x, 0) + acc end)
  end

end

1 个答案:

答案 0 :(得分:0)

您的地图太小,无法从使用Flow中获益。在处理非常大的甚至无限期集合时,流程非常棒,因为这样可以在几个核心上运行应用程序。但是,Flow需要一些时间来初始化,并且后台的整个操作也需要一些时间,所以在你的情况下使用它是没有意义的。

您应该尝试使用Enum模块优化方法 - 对于这样的小地图,此模块就足够了。您可以更改合并列表的方式而不是

a ++ b ++ c

你可以使用更高效的东西。

每当你使用这个组合列表时,你应该从变量中获取它 - 而不是一直计算它。

watch more here了解Flow所需的开销。