Как распараллелить внешние вызовы API с помощью Elixir, чтобы сделать их очень быстрыми
Я работаю над приложением Phoenix, которое использует API Instagram через Эликстаграмма библиотека. Есть конкретная страница, на которой мне нужно отобразить группу пользователей, которых нужно получить из API… Вот код «до» (последовательный):
def users_list(%Account{favourite_users: users}) do
Elixtagram.configure
users
|> Enum.map(fn(u) -> Elixtagram.user(u.ig_id).username end)
|> Enum.join(", ")
end
Здесь я просто передаю список идентификаторов Instagram и возвращаю строку имен пользователей, разделенных запятыми. Очевидная проблема здесь заключается в том, что Elixtagram выполняет вызов API, который может занять относительно большое количество миллисекунд, и глупо ждать завершения каждого из них, прежде чем запускать следующий, особенно когда мы используем язык с таким легкодоступным параллелизм как Эликсир.
Вот «фиксированный» код:
def users_list(%Account{favourite_users: users}) do
Elixtagram.configure
users
|> Enum.map(fn(u) -> Task.async(fn -> Elixtagram.user(u.ig_id).username end) end)
|> Enum.map(&Task.await/1)
|> Enum.join(", ")
end
Разница здесь в том, что вместо блокировки для каждого запроса в Enum.map я заполняю список асинхронными задачами, которые затем жду в следующей строке. Это означает, что количество запросов, которые мы делаем здесь, мало влияет на производительность кода (пока мы не перегрузим сеть…).
Удачи в ваших параллельных приключениях, друзья!