首页 > 解决方案 > Task.start Elixir 中的奇怪行为

问题描述

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

演员.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他们都没有启动异步任务。

标签: erlangelixirtaskdistributed-computingdistributed

解决方案


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

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

• 利用mix run --no-halt

• 创建一个Application

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


推荐阅读