読者です 読者をやめる 読者になる 読者になる

プログラマーな日々

プログラマーをやっています。好きなツール:WorkFlowy、好きな言語:C#、好きなサービス:Backlog、好きなAWS:AWS Lambda。

わんくま同盟 東京勉強会 #89に行ってきた(その3 async/awaitの基本 by 荒井省三さん)

イベント 非同期

f:id:JHashimoto:20140409044240j:plain

4/5に、わんくま同盟 東京勉強会 #89に行ってきました。

わんくま同盟
わんくま同盟 東京勉強会 #89

 

全4回に分けて、セッションの内容を紹介します。今回は第3回です。

3つ目のセッションは、荒井省三さんの「async/awaitの基本」でした。

非同期プログラミングとは

  • 演算子というよりオペレーターである
  • メインスレッドと異なるスレッドを利用ということ
  • 処理結果をほしいかどうかは使い方しだい
  • メインスレッドが終わるとプロセスが終わるので、非同期スレッドも終わる

非同期を使う理由

  • 目的は応答なしを防止したい
  • ForkしてJoinする(分岐して結果を集める)
  • ある一定数以上は分岐できない
    • アムダールの法則

非同期の手法

  • スレッド
  • スレッドプール
    • OSが勝手な順番で実行する
  • Dispacher.BeginInvoke
    • キューを持っていることがスレッドプールとは違う
      • 順番どおりに実行
      • プライオリティを変えられる

非同期の課題

  • スレッドに入れたものの処理順序をどうやって保証したいか
  • メインのスレッドとどうやって同期するか
    • イベントを使うのが王道
    • それ以外の方法はマシン依存になってしまう
      • 開発機で動作しても本番機で動作するかわからない
  • スレッドで処理した結果の受け取り
    • デッドロックの可能性がある
    • メモリアライメントを意識する必要がある
    • イベント引数をつかうのが安全
      • 値渡しだから

非同期プログラミングモデル(APM)

  • Begin~、End~を使ったコールバックモデル
  • すべての根本、基本
  • でも書くのは面倒くさい

イベントベース非同期パターン(EAP)

  • APMをイベントでラップした非同期プログラミングパターン

タスクベース非同期パターン(TAP)

  • Taskオブジェクトでラップしたもの

PLINQ

  • データ並列に使える
  • データを勝手にパーティショニングして、スレッドに振り分けてくれる
  • 例:URlをコレクションにいれておくと、並列にリクエストを送れる

async/awaitパターン

  • async/awaitオペレーターを使う
  • asyncを書くと非同期メソッドになる
  • awaitを書くと結果を受け取れる

デモ

  • 同期処理
    • 処理が終わるまでUIが固まる
  • 単純にワーカースレッドに切り出す
    • 結果を受け取れない
  • ワーカースレッドが終わった後Joinする
    • 結果を待つためにJoinするので、応答なしの瞬間が発生する
  • スレッドプール使用
    • 応答なしにならない
    • スレッドプールが終わったかわからない
    • 結果を受け取れない
  • async
    • 結果を順番に取得できる
    • C#コンパイラがコードを生成するためのもの
    • Refrectorで自動生成されるソースコードを見てみる
      • d__0とは、IAsyncStateMashineを実装する構造体
      • AsyncVoidMethodddBuilderを呼び出す
      • SyncronizationContextをprivateのフィールドで持っている
        • UIスレッドと同期するため
      • awaitを複数書くと、IAsyncStateMashineを実装する構造体が複数作成される
    • 戻り値にはTask<T>以外は使わないこと

非同期メソッドの基本原則

  • Immutableなメソッドが基本
    • 引数によってのみ戻り値が変わる
    • 副作用がない

同期メソッドとして扱う

  • Task.GetAwaiter.GetResults
  • ストアアプリ
    • IAsyncAction、IAsyncOperation、IAsyncXXXWithProgress<T>、
    • TaskAwaiterを使えば、Completedイベントで結果を受け取れる
      • 例:コンストラクタ(async,awaitは使えない)

まとめ

  • awaitを2つ書いた瞬間に、はまる可能性が発生する
    • awaitを複数使う場合、Task.ConfigureAwaitでSyncronizationContextを無効にできる
    • ただし自分で結果を受け取るコードをかかなければならない
  • async,awaitは非同期処理の課題を解決してはくれない
  • Immutableにすることを心掛ける
  • メモリアライメントに注意しないと、デッドロックが起こり得る
  • aysnc使うと呼び出し側では一瞬で処理が終わる
    • 破綻しないのは呼び出し側のスレッドが残ってるから
  • タイマーでのポーリングはマシン依存になるので、結果を受け取るのに使ってはいけない

リンク

第1回のリンクです。

わんくま同盟 東京勉強会 #89に行ってきた(その1 MonoGame で作る C# ゲームプログラミング!) - プログラマーな日々

 

第2回のリンクです。

わんくま同盟 東京勉強会 #89に行ってきた(その2 Knockout.js の利用とカスタムバインディングの利用) - プログラマーな日々

 

第4回のリンクです。

わんくま同盟 東京勉強会 #89に行ってきた(その4 Dynamics CRM Online を使ってみよう by えムナウさん) - プログラマーな日々