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

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

Sponsored · Ship Features Fearlessly Turn features on and off without deploys. Used by thousands of Ruby developers.

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

Avatar for enpedasi

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", "ベトナム料理", %{}},