параллельная или асинхронная задача для функций в эликсире от golang и c # - PullRequest
0 голосов
/ 12 сентября 2018

Я изучаю Эликсир с Фениксом. Я легко создал несколько серверов REST API, но есть еще одно требование, которое мне нужно выполнить. Мне нужно иметь возможность выполнять параллельные или асинхронные задачи для вызова / выполнения некоторого API из внутреннего интерфейса и поместить эти результаты в ответ JSON.

Вот как бы я это реализовал примерно из Go и C #

// Golang
userCount := make(chan int)
usersList := make(chan []Users)

go getAggregateUserCounts(userCount)
go getGetUsersList(usersList)

// do other heavy tasks from here

httpJsonResponse(map[string]interface{}{
    "test":       1,
    "user_count": <-userCount,
    "users_list": <- usersList ,
})



// C# or dotnetcore
public async Task<JsonResult> GetJson(string dbName, string collection)
{
    using(var client = new MongoDBCon())
    {
        // some heavy computations
        var documents = await col.FindAsync<Users>(FilterDefinition<Users>.Empty);
        return Json(new {
              users_count: await documents.ToListAsync().Result.Count,
              users: await users.GetusersList()
        });
    }
}

Пока что у меня есть эликсир:

// Elixir
def start do
  IO.puts "starting.."
  response = %{}
  1..3
  |> Enum.map(fn(id) -> async_get_request(id) end)
  |> Enum.each(
    fn(_) -> 
      item = get_result()
      IO.inspect :"#{item[:user][:id]}"
      IO.inspect item[:user]

      # Map.put(response, :"#{item[:user][:id]}", item[:user])
    end)

  IO.puts "done.."
  IO.inspect response
end

def start2 do
  IO.puts "start2.."
  res = %{
    "item" => Task.async(fn -> IO.puts "weee" end) 
  }
end

def get_request(id) do
  sleep = :rand.uniform(10)
  :timer.sleep(sleep)  
  %{user: %{id: id, sleep: sleep}}
end  

def async_get_request(id) do
  caller = self()
  spawn(fn ->  
    send(caller, {:result, get_request(id)})  
  end)      
end

def get_result do
  receive do
    {:result, result} -> result
  end
end

результат

iex(3)> Para.start
starting..
%{id: 2, sleep: 1}
%{id: 3, sleep: 3}
%{id: 1, sleep: 9}
done..
%{}

что я хочу - это

%{
 id: 2, {id: 2, sleep: 1},
 id: 3, {id: 3, sleep: 3},
 id: 1, {id: 1, sleep: 9}
 }

Приведенный выше пример предназначен только для обучения или практики, но для реального мира я бы предпочел добавить значения на карту с помощью некоторых параллельных задач.

Я не уверен, возможно ли это с эликсиром.

 %{
    "users_count": AsyncUsersModule.GetUsersTotal(),
    "users_list": AsyncUsersModule.GetUsersList()
 }

и ответ в json должен быть

{
  "users_count": 10000,
  "users_list": []
}

Я знаю, что мне все еще нужно много практиковаться и читать, мне просто нужна помощь.

1 Ответ

0 голосов
/ 12 сентября 2018

Я считаю, что вам нужно Task.yield_many/2 и Kernel.SpecialForms.for/1 для обработки результата:

results = 
  1..3
  |> Enum.map(&Task.async(fn -> get_request(&1) end))
  |> Task.yield_many()

for { _, {:ok, value}} <- results, do: IO.inspect(value)
...