Upgrade to Pro — share decks privately, control downloads, hide ads and more …

Elixir はじめての並列処理 (仮)

Elixir はじめての並列処理 (仮)

enpedasi

April 17, 2018
Tweet

More Decks by enpedasi

Other Decks in Programming

Transcript

  1. まずはiexで対話環境を実⾏。 引数なしで1を返すだけの関数を、タスクに登録。 iex(1)> task_id = Task.async(fn -> 1 end) %Task{

    owner: #PID<0.272.0>, pid: #PID<0.2398.0>, ref: #Reference<0.4175548739.2466250754.158616> } タスクIDにはTask構造体が帰ってきます。 iex(1)> Task.await(task_id) 1 task_idを⼿掛かりに値を取り出すことができまし た。
  2. 5秒待って1返す関数を登録します iex(1)> task_id = Task.async(fn -> Process.sleep(5000); \ 1 end)

    iex(2)> Task.await(task_id) 1 (1)の後(2)を即実⾏すれば数秒待って、1が帰ってき ます。 JavascriptのPromise/thenやasync/awaitと同じイメ ージです。 ただし、Elixirではプロセスにタスクを任せていま す。
  3. 1から10までの数字を5秒後それぞれを返すタスク を⽣成 iex> tasks = 1..10 \ |> Enum.map(fn i

    -> \ Task.async(fn -> Process.sleep(5000);\ i end) \ end) タスクidのリストがすぐに戻ってくるので map関数で取り出します。 iex> tasks |> Enum.map( &Task.await &1 ) [1, 2, 3, 4, 5, 6, 7, 8, 9, 10] 10個のタスクを同時に捌くことができました。
  4. 今度は10000個のタスクを⽴ち上げてみます iex> tasks = 1..10_000 \ |> Enum.map(fn i ->

    \ Task.async(fn -> Process.sleep(5000);\ i end) \ end) タスク登録に1秒かかりません。 iex> tasks |> Enum.map( &Task.await &1 ) [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37 43, 44, 45, 46, 47, 48, 49, 50, ...] 即レスポンスが帰ってきます。
  5. 準備 プロジェクト作成 iex phx.new gourumet --no-ecto --no-brunch cd gorumet mix.exs

    def deps do [{ ︓httpoison、"〜> 1.0 " }] #追加 end mix deps.get
  6. 2つのサービスを呼び出して結果をまとめます iex> shops = [ GuruNaviApi.get_shops({"福岡市中央区","ベトナム料理"}), HotPepperApi.get_shops({"福岡市中央区","ベトナム料理"}) ] iex> shops

    |> Enum.map(fn r -> r[:shops] end) |> List.flatten |> Enum.sort( fn {a, _, _, _}, {b, _, _, _} -> a<=b end ) [ {"Part du monde ", "050-3461-6009", "ハンモックカフェ", " 12:00〜20:30(L.O.20:00)"}, {"Xinchao ", "050-3373-1681", "ベトナム居酒屋", "⽉〜⽇ ランチ︓11:00〜14:00<BR>⽉〜⽇ ディナー︓18:00〜23:00" {"ゴンゴン ngon ngon", "N/A", "ベトナム料理", "⽕〜⽇、祝⽇、祝前⽇: 12:00〜15:00 (料理L.O. 14:30)17:30〜23:00
  7. 以下は定義した時点で、APIが逐次実⾏されるので shops = [ GuruNaviApi.get_shops({"福岡市中央区","ベトナム料理"}), HotPepperApi.get_shops({"福岡市中央区","ベトナム料理"}) ] 匿名関数のリストに置き換えます。 addr_a =

    "福岡市中央区" addr_b = "福岡市博多区" # 博多区参戦! dish = "ベトナム料理" reqs = [ fn -> GuruNaviApi.get_shops({addr_a, dish}) end, fn -> HotPepperApi.get_shops({addr_a, dish}) end, fn -> GuruNaviApi.get_shops({addr_b, dish}) end, fn -> HotPepperApi.get_shops({addr_b, dish}) end, ]
  8. Taskに投げて並⾏リクエストを⾏います。 shops = reqs |> Enum.map( &Task.async(&1) ) |> Enum.map(

    &Task.await(&1) ) ⼊れ⼦のリストを平たくして、ソート List.flatten(shops) |> Enum.sort( fn {a,_,_,_},{b,_,_,_} -> a < b end ) [ {"モン アン エスニック ", "092-722-6860", "ベトナム料理", %{}}, {"ベトナム料理SAI‐GON ", "092-721-1284", "ベトナム料理", %{}}, {"ベトナムビストロ asiatico ", "092-725-6684", "貸切、⼥⼦会、ワイン", "⽕〜⾦ ランチ︓12:00〜15:00<BR>⼟・⽇・祝⽇ 12:00〜17:00(※平⽇・⼟ {"ベトナムカフェレストラン ゴンゴン ", "092-403-6689", "ベトナム料理", %{}},