【问题标题】:Weird behaviour in Task.start ElixirTask.start Elixir 中的奇怪行为
【发布时间】:2019-03-04 23:15:23
【问题描述】:

我正在尝试使用 GenServer 在 Elixir 中编写一个 Gossip Simulator。我有一个 main() 方法,它充当创建网络拓扑的客户端并启动所有参与者(GenServer 的)。然后它向一个 Actor 发送一个Genserver.cast() 来发起八卦。 Actor 在其handle_cast() 中启动一个Task.start() 以开始与其他actor 闲聊。看起来我没有以正确的方式使用Task.start()(actor.ex 中的第 16 行),因为被调用的任务 startGossiping() 永远不会执行,Task.start() 之后的语句也不会执行。混合只是退出而不给出任何错误。缩短的程序如下所示。

actor.ex -

defmodule Actor do    
    use GenServer

    def init([nodeId, neighborList, algorithm]) do
        inspect "#{nodeId}"
        recCount = 1
        gossipingTask = 0
        {:ok, {nodeId, neighborList, algorithm, recCount, gossipingTask}}#nodeId, neighborList, algorithm, receivedCount
    end

    def handle_cast({:message, rumour}, state) do
        {nodeId, neighborList, algorithm, recCount, gossipingTask} = state
        IO.puts "nodeId - #{nodeId} recCount - #{recCount} handle_cast: #{rumour} gossipingTask - #{gossipingTask}"
        nL = elem(state, 1)
        IO.puts "here #{rumour}"
        gossipingTask = Task.start(fn -> startGossiping(nL, rumour) end) 
        IO.puts "Now again - #{rumour}"
        {:noreply, {nodeId, neighborList, algorithm, recCount + 1, gossipingTask}}
    end

    def startGossiping(nL, rumour) do
        IO.puts "In startGossiping "
        #{Enum.random(nL)}"
        # GenServer.cast(Proj2.intToAtom(Enum.random(nL)), {:message, rumour})
    end
end

proj2.ex -

defmodule Proj2 do
# Instructions to run the project
# 1) $mix escript.build
# 2) $escript proj2 100 full gossip

    def main(args) do
        # Receive total number of nodes, topology, algorithm, triggerNodes(optional), threshold(optional) from user.
        # Read README.md for more details
        numOfNodes = String.to_integer(Enum.at(args, 0))
        topology = Enum.at(args, 1)
        algorithm = Enum.at(args, 2)
        numOfNodes = if String.contains?(topology, "2d"), do: round(:math.pow(round(:math.sqrt(numOfNodes)), 2)), else: numOfNodes

        case topology do
            "full"          ->
                Enum.each 1..numOfNodes, fn nodeId ->
                    neighborList = getNeighborsFull(nodeId, numOfNodes)
                    inspect neighborList
                    nodeId_atom = intToAtom(nodeId)
                    GenServer.start_link(Actor, [nodeId, neighborList, algorithm], name: nodeId_atom)
                    # IO.puts "In main, nodeId = #{nodeId}"
                end
        end
        GenServer.cast(intToAtom(2), {:message, "This is Elixir Gossip Simulator"})

    end

    def getNeighborsFull(nodeId,numOfNodes) do
        range = 1..numOfNodes
        range
        |> Enum.filter(fn(value) -> value != nodeId end)
        |> Enum.map(fn(filtered_value) -> filtered_value * 1 end)
        # IO.inspect Neighboringlist
    end

    def intToAtom(integer) do
        integer |> Integer.to_string() |> String.to_atom()
    end
end

更新: 还没弄清楚问题所在。我实际上无法启动任何并发进程。 spawn、start_link、Task 他们都没有启动异步任务。

【问题讨论】:

  • 你想如何运行它?
  • 1) $ mix escript.build 2) $ escript proj2 2 full gossip 。输出 - nodeId - 2 recCount - 1 handle_cast: This is Elixir Gossip Simulator gossipingTask - 0 here This is Elixir Gossip Simulator $

标签: erlang elixir task distributed-computing distributed


【解决方案1】:

GenServer.cast/3 和 Task.start/1 都不会阻止您的应用程序退出。

我不确定您为什么要构建escript 来测试代码。您有以下选项等待执行完成后再退出(包括但不限于):

• 使用mix run --no-halt

• 创建Application

• 启动链接的任务并在代码中的某处使用Task.await/2 等待任务完成。

【讨论】:

  • 我尝试在 iex shell 中分别运行代码 - 1) $c("proj2.ex") 2) $c("actor.ex") 3) $Proj2.main (硬编码参数),它似乎工作正常!它正在执行任务。问题似乎与我运行程序的方式有关。我不确定如何使用 $mix run 因为它需要一个 .exs 文件。会尽快更新。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2018-01-25
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2018-11-06
  • 2012-09-01
  • 2012-02-02
相关资源
最近更新 更多