SlideShare a Scribd company logo
.NET Web プログラミングにおける
非同期 I/O のすべて
日本マイクロソフト株式会社
エバンジェリスト
松崎 剛
http://blogs.msdn.com/b/tsmatsuz
2
セッション ゴール
• .NET Web 開発における非同期 IO の基本を学ぶ
発想の原点や歴史、基本メカニズム、用語などについて
• べし・べからず、Tips、などを理解
新機能にはワケがある !
~ スケーラブルな Web を作ろう ~
3
非同期のプログラミング・パターン
• EAP (Event-based Asynchronous Pattern)
• APM (Asynchronous Programming Model)
• TAP (Task-based Asynchronous Pattern)
FileStream fs;
byte[] readArray = new byte[0x1000];
. . .
fs.BeginRead(readArray, 0, readArray.Length,
new AsyncCallback(readCallback), fs);
. . .
private void readCallback(IAsyncResult ar)
{
System.IO.FileStream fs =
(System.IO.FileStream)ar.AsyncState;
int fsize = fs.EndRead(ar);
. . .
}
MyReadClass myRead = new MyReadClass();
myRead.ReadCompleted +=
new EventHandler<ReadCompletedEventArgs>(
readCompleted);
myRead.ReadAsync();
. . .
private void readCompleted(
object sender, ReadCompletedEventArgs e)
{
var res = e.Result;
. . .
}
using (StreamReader reader = File.OpenText(filename))
{
result = new char[reader.BaseStream.Length];
Task<int> t = reader.ReadAsync(result, 0, (int) reader.BaseStream.Length);
}
4
ASP.NET における非同期の変遷
ASP.NET Web フォーム ASP.NET MVC
.NET 2.0
.NET 3.5
.NET 4.5
.NET 4.0
5
プログラミング・パターンの相性
protected void Page_Load(object sender, EventArgs e)
{
if (!IsPostBack)
{
this.PreRenderComplete +=
new EventHandler(Page_PreRenderComplete);
AddOnPreRenderCompleteAsync(
new BeginEventHandler(BeginAsyncOperation),
new EndEventHandler(EndAsyncOperation));
}
}
IAsyncResult BeginAsyncOperation(object
sender, EventArgs e, AsyncCallback cb, object state)
{
_connection = new SqlConnection(connectstring);
_connection.Open();
_command = new SqlCommand(
"SELECT title_id, title, price FROM titles",
_connection);
return _command.BeginExecuteReader(cb, state);
}
void EndAsyncOperation(IAsyncResult ar)
{
_reader = _command.EndExecuteReader(ar);
}
protected void Page_PreRenderComplete(object
sender, EventArgs e)
{
Output.DataSource = _reader;
Output.DataBind();
}
ASP.NET Async Page (APM)
+
DB Access (APM)
6
TAP + async/await (C# 5.0)
public Task<ActionResult> Test1()
{
// Step 1
HttpClient cl = new HttpClient();
Task<HttpResponseMessage> task = cl.GetAsync(@"http://heavyweb.cloudapp.net/");
return task.ContinueWith(t =>
{
// Step 2
ViewBag.ResultData = t.Result.ToString();
return (ActionResult)View();
});
}
public async Task<ActionResult> Test1()
{
// Step 1
HttpClient cl = new HttpClient();
HttpResponseMessage result = await cl.GetAsync(@"http://heavyweb.cloudapp.net/");
// Step 2
ViewBag.ResultData = result.ToString();
return (ActionResult)View();
}
7
ASP.NET における非同期
要求 (Request)、キュー (Queue)、スレッド (Thread)
Web サーバー (IIS)
要求 (Request)
キュー (Queue)
処理中 …
処理中 …
処理中 …
スレッド (Thread)
スレッド プール
8
ASP.NET における非同期
同期のケース
お医者さん
=
スレッド (Thread)
患者さん
=
要求 (Request)
受付
=
キュー (Queue)
9
ASP.NET における非同期
同期のケース
10
ASP.NET における非同期
同期のケース
空くのを待機 . . .
11
ASP.NET における非同期
非同期のケース
12
ASP.NET における非同期
非同期のケース
13
ASP.NET における非同期
非同期のケース
14
I/O Completion Port (IOCP)
• Windows が提供する機構
• 1 つの IOCP は、1 つ以上のデバイス ハンドル (ファイル ハンドルな
ど) と関連
• キューのメカニズムを使って、非同期 IO の完了をプログラムから検知
• スレッドの状態 (待ち状態、リリース状態、など) を監視し、スレッド
の実行数を自動で制御
• IOCP でブロックされたスレッドは、いったん解放されて、LIFO の
キューに入る (1 つのスレッドが継続して処理可能。可能な限り
Context Switch を抑制)
• Win32 API を提供
• カスタムな制御が可能
• Thread Pool API を使った I/O 処理、Timer処理 (Thread Pool Timer)
で使用
15 15
16 16
public class Handler1 : IHttpHandler
{
public void ProcessRequest(HttpContext context)
{
if (context.IsWebSocketRequest)
{
BetsHandler1 handler = new BetsHandler1();
context.AcceptWebSocketRequest(handler.Receive);
}
else
{
context.Response.StatusCode = 400; //bad request
}
}
. . .
}
public class BetsHandler1
{
public WebSocket webSocket;
public async Task Receive(
AspNetWebSocketContext context)
{
webSocket = context.WebSocket;
ArraySegment<byte> buf =
new ArraySegment<byte>(new byte[2048]);
while (true)
{
WebSocketReceiveResult res =
await webSocket.ReceiveAsync(
buf,
System.Threading.CancellationToken.None);
if (res.MessageType ==
WebSocketMessageType.Close)
{
// Close Message
connectedHandlers.Remove(this);
await webSocket.CloseOutputAsync(
. . .);
break;
}
else if (res.MessageType ==
WebSocketMessageType.Text)
{
// Text Message
. . . Some kind of process
}
}
}
. . .
}
17 17
public class Handler1 : IHttpHandler
{
public void ProcessRequest(HttpContext context)
{
if (context.IsWebSocketRequest)
{
BetsHandler1 handler = new BetsHandler1();
context.AcceptWebSocketRequest(handler.Receive);
}
else
{
context.Response.StatusCode = 400; //bad request
}
}
. . .
}
public class BetsHandler1
{
public WebSocket webSocket;
public Task Receive(
AspNetWebSocketContext context)
{
webSocket = context.WebSocket;
ArraySegment<byte> buf =
new ArraySegment<byte>(new byte[2048]);
while (true)
{
WebSocketReceiveResult res =
webSocket.ReceiveAsync(
buf,
System.Threading.CancellationToken.None);
if (res.MessageType ==
WebSocketMessageType.Close)
{
// Close Message
connectedHandlers.Remove(this);
webSocket.CloseOutputAsync(
. . .);
break;
}
else if (res.MessageType ==
WebSocketMessageType.Text)
{
// Text Message
. . . Some kind of process
}
}
return new TaskFactory().StartNew(() => { });
}
. . .
}
18
.NET 4.5 Web の TAP 対応 (“呼ぶ” 側)
• ASP.NET Web フォーム
• ASP.NET Web API
• WCF
• WebSocket
. . .
protected void Page_Load(object sender, EventArgs e)
{
Page.RegisterAsyncTask(new PageAsyncTask(async () =>
{
HttpClient cl = new HttpClient();
HttpResponseMessage res =
await cl.GetAsync(@“http://.../");
Label1.Text = res.ToString();
}));
}
public class Service1 : IService1
{
public async Task<string> GetDataAsync()
{
HttpClient cl = new HttpClient();
HttpResponseMessage res =
await cl.GetAsync(@“http://.../");
return res.ToString();
}
}
public class ValuesController : ApiController
{
// GET api/values
public async Task<string> Get()
{
HttpClient cl = new HttpClient();
HttpResponseMessage res =
await cl.GetAsync(@"http://.../");
return res.ToString();
}
}
context.AcceptWebSocketRequest(handler.Receive);
. . .
public async Task Receive(AspNetWebSocketContext context)
{
while (true)
{
WebSocketReceiveResult res =
await context.WebSocket.ReceiveAsync(. . .);
. . .
}
}
19
IO リソースの TAP 対応 (“呼ばれる” 側)
ファイル入出力 .NET 4.5 で TAP (async) のメソッド (ReadAsync, WriteAsync,
CopyToAsync など) を提供 (これまでは、APM のみ)
データ
ベース
ADO.NET .NET 4.5 で TAP (async) のメソッド (ReadAsync など) を提供
(これまでは、APM のみ)
Entity
Framework
Entity Framework 6 で、TAP (async) をサポート
(現在、ベータ版を提供)
ネット
ワーク
REST HttpClient のメソッドは、基本的に TAP ベース
WCF .NET 4.5 で自動生成される Service Refrence Proxy では、TAP
(async) のメソッドを提供
クラウド Windows Azure
ServiceBus
最新の WindowsAzure.ServiceBus パッケージ (NuGet) で TAP の
メソッド (NamespaceManager.QueueExistsAsync など) を提供
(APM も使用可能)
では、未対応のものはどうする ?
(例 : WCF Data Services, Windows Azure Storage など)
ますます、対応中 . . . (こうご期待!)
20
SynchronizationContext
• スレッド間の関係を管理する抽象化されたスケジューラー・オブジェクト
 ASP.NET 非同期スレッドは、Win32 メッセージ ループのように特定スレッドに紐づかない
• 1 つのスレッドに対し、必ず 1 つの SynchronizationContext が存在 (ただし、単一
のSynchronizationContext は複数スレッドで共有)
• 一部の実装 (override メソッド) を除き、具体的な実装は派生クラスに依存
 WindowsFormsSynchronizationContext
 DispatcherSynchronizationContext
 AspNetSynchronizationContext
 既定の SynchronizationContext
• これまでの非同期処理 (EAP など) において、その動作をつかさどる
• TAP では TaskScheduler を使用 (SynchronizationContext を使用する際は、
TaskScheduler.FromCurrentSynchronizationContext を明示)
21
SynchronizationContext
• 既定の Awaiter (TaskAwaiter) は、Current の SynchronizationContext を使用
(なければ TaskScheduler も参照)
 AspNetSynchronizationContext では、同期ブロックに入れるスレッドは 1 つだけ
• .NET 4 以降では、Task と相性の良い新しい AspNetSynchronizationContext を使用
 従来のものは LegacyAspNetSynchronizationContext に変更
この場合でも、Web.configの設定で新しいContextを
使用可能
<appSettings>
<add
key="aspnet:UseTaskFriendlySynchronizationContext“
value="true"/>
</appSettings>
22
混ぜるな、危険 💀
• Async (EAP, TAP, etc) と Sync の混
在プログラムは、デッドロックの原因
となる !
Task で受け取った内容を、むりやり同期
化しない (All async is beautiful !)
「扱いやすい」(理解しやすい) という理
由だけで、 Result、Wait を多用しない
(初心者にありがちなミス)
現実の開発では、追跡とデバッグが非常に
困難 (例 : 単一では動作するんだけ
ど ?、コンソール・アプリでは動くのに ?
など)
.NET Web プログラミングにおける非同期 IO のすべて (Build Insider OFFLINE)

More Related Content

PPTX
An other world awaits you
信之 岩永
 
PDF
ブロックチェーン統合ツールCactusとトークンエコノミー実現への期待
LFDT Tokyo Meetup
 
PDF
初心者向けCTFのWeb分野の強化法
kazkiti
 
PDF
Kibanaでsysstatを可視化する
Kensuke Maeda
 
PDF
老舗メーカーにアジャイル型要求開発を導入してみました(中原慶)
Kei Nakahara
 
PPTX
分散システムについて語らせてくれ
Kumazaki Hiroki
 
PDF
ワンランク上のゲームデザイン・レベルデザイン・UIデザインを考える 「コンテキスト」「コンフリクト」「コントラスト」デザイン
Kouji Ohno
 
PPTX
よわよわPCによる姿勢推定 -PoseNet-
Yuto Mori
 
An other world awaits you
信之 岩永
 
ブロックチェーン統合ツールCactusとトークンエコノミー実現への期待
LFDT Tokyo Meetup
 
初心者向けCTFのWeb分野の強化法
kazkiti
 
Kibanaでsysstatを可視化する
Kensuke Maeda
 
老舗メーカーにアジャイル型要求開発を導入してみました(中原慶)
Kei Nakahara
 
分散システムについて語らせてくれ
Kumazaki Hiroki
 
ワンランク上のゲームデザイン・レベルデザイン・UIデザインを考える 「コンテキスト」「コンフリクト」「コントラスト」デザイン
Kouji Ohno
 
よわよわPCによる姿勢推定 -PoseNet-
Yuto Mori
 

What's hot (20)

PPTX
ドライブレコーダの動画を使った道路情報の自動差分抽出
Tetsutaro Watanabe
 
PDF
ユーザーストーリー駆動開発で行こう。
toshihiro ichitani
 
PDF
Ooc 2020
Zenji Kanzaki
 
PDF
chatGPTの驚くべき対話能力.pdf
YamashitaKatsushi
 
PDF
ドメイン駆動設計 ( DDD ) をやってみよう
増田 亨
 
PPTX
車両運行管理システムのためのデータ整備と機械学習の活用
Eiji Sekiya
 
PDF
リクルートのWebサービスを支える共通インフラ「RAFTEL」
Recruit Technologies
 
PDF
ディープラーニングのフレームワークと特許戦争
Yosuke Shinya
 
PDF
5分でわかるクリーンアーキテクチャ
Kenji Tanaka
 
PDF
ソフトウェアテストの歴史と近年の動向
Keizo Tatsumi
 
PDF
今さら聞けないXSS
Sota Sugiura
 
PDF
立教大学MBA:AIの最先端技術によるこれからの価値創造
Osaka University
 
PDF
「いい検索」を考える
Shuryo Uchida
 
PDF
失敗から学ぶ機械学習応用
Hiroyuki Masuda
 
PPTX
論文に関する基礎知識2016
Mai Otsuki
 
PDF
相互情報量を用いた独立性の検定
Joe Suzuki
 
PDF
あなたの業務に機械学習を活用する5つのポイント
Shohei Hido
 
PDF
45分間で「ユーザー中心のものづくり」ができるまで詰め込む
Yoshiki Hayama
 
PDF
学位論文の書き方メモ (Tips for writing thesis)
Nobuyuki Umetani
 
PDF
BlackBox モデルの説明性・解釈性技術の実装
Deep Learning Lab(ディープラーニング・ラボ)
 
ドライブレコーダの動画を使った道路情報の自動差分抽出
Tetsutaro Watanabe
 
ユーザーストーリー駆動開発で行こう。
toshihiro ichitani
 
Ooc 2020
Zenji Kanzaki
 
chatGPTの驚くべき対話能力.pdf
YamashitaKatsushi
 
ドメイン駆動設計 ( DDD ) をやってみよう
増田 亨
 
車両運行管理システムのためのデータ整備と機械学習の活用
Eiji Sekiya
 
リクルートのWebサービスを支える共通インフラ「RAFTEL」
Recruit Technologies
 
ディープラーニングのフレームワークと特許戦争
Yosuke Shinya
 
5分でわかるクリーンアーキテクチャ
Kenji Tanaka
 
ソフトウェアテストの歴史と近年の動向
Keizo Tatsumi
 
今さら聞けないXSS
Sota Sugiura
 
立教大学MBA:AIの最先端技術によるこれからの価値創造
Osaka University
 
「いい検索」を考える
Shuryo Uchida
 
失敗から学ぶ機械学習応用
Hiroyuki Masuda
 
論文に関する基礎知識2016
Mai Otsuki
 
相互情報量を用いた独立性の検定
Joe Suzuki
 
あなたの業務に機械学習を活用する5つのポイント
Shohei Hido
 
45分間で「ユーザー中心のものづくり」ができるまで詰め込む
Yoshiki Hayama
 
学位論文の書き方メモ (Tips for writing thesis)
Nobuyuki Umetani
 
BlackBox モデルの説明性・解釈性技術の実装
Deep Learning Lab(ディープラーニング・ラボ)
 
Ad

Viewers also liked (10)

PPTX
非同期処理の基礎
信之 岩永
 
PDF
よりよい開発を目指すための、プロセス&ツール活用
Kaoru NAKAMURA
 
PDF
50分で掴み取る ASP.NET Web API パターン&テクニック
miso- soup3
 
PDF
Build Insider OFFLINE vol.01 スマートフォンサイトのこれから ~ レスポンシブ・Webデザインは救世主となり得るか
H2O Space. Co., Ltd.
 
PDF
Beachhead implements new opcode on CLR JIT
Kouji Matsui
 
PDF
C#次世代非同期処理概観 - Task vs Reactive Extensions
Yoshifumi Kawai
 
PDF
Buildinsider OFFLINE TypeScriptの基礎から実践・利用事例まで
Masahiro Wakame
 
PDF
スケーラビリティと耐障害性を両立するWeb アプリケーション
Masayoshi Hagiwara
 
PPTX
HttpClient詳解、或いは非同期の落とし穴について
Yoshifumi Kawai
 
PDF
スマホ向けWebアプリ開発で使えるフロントエンド高速化手法
Eiji Kodama
 
非同期処理の基礎
信之 岩永
 
よりよい開発を目指すための、プロセス&ツール活用
Kaoru NAKAMURA
 
50分で掴み取る ASP.NET Web API パターン&テクニック
miso- soup3
 
Build Insider OFFLINE vol.01 スマートフォンサイトのこれから ~ レスポンシブ・Webデザインは救世主となり得るか
H2O Space. Co., Ltd.
 
Beachhead implements new opcode on CLR JIT
Kouji Matsui
 
C#次世代非同期処理概観 - Task vs Reactive Extensions
Yoshifumi Kawai
 
Buildinsider OFFLINE TypeScriptの基礎から実践・利用事例まで
Masahiro Wakame
 
スケーラビリティと耐障害性を両立するWeb アプリケーション
Masayoshi Hagiwara
 
HttpClient詳解、或いは非同期の落とし穴について
Yoshifumi Kawai
 
スマホ向けWebアプリ開発で使えるフロントエンド高速化手法
Eiji Kodama
 
Ad

Similar to .NET Web プログラミングにおける非同期 IO のすべて (Build Insider OFFLINE) (20)

PDF
async/await不要論
bleis tift
 
PDF
Windows 8時代のUXを支える非同期プログラミング
Yuya Yamaki
 
PDF
これからの「async/await」の話をしよう
Kouji Matsui
 
PPTX
async/await のしくみ
信之 岩永
 
PPTX
C# 8.0 非同期ストリーム
信之 岩永
 
PDF
いまさら恥ずかしくてAsyncをawaitした
Kouji Matsui
 
PDF
Mono is Dead
melpon
 
PDF
Reactive Extensionsで非同期処理を簡単に
Yoshifumi Kawai
 
PDF
パターンでわかる! .NET Coreの非同期処理
Kouji Matsui
 
PDF
.NET最先端技術によるハイパフォーマンスウェブアプリケーション
Yoshifumi Kawai
 
PPTX
Reactive
Akihiro Ikezoe
 
PDF
【Unite Tokyo 2018】さては非同期だなオメー!async/await完全に理解しよう
Unity Technologies Japan K.K.
 
PPTX
Windows Store App HTTP通信を振り返る
Tomonori Ohba
 
PDF
トランザクションの並行処理制御
Takashi Hoshino
 
PPTX
Non blocking and asynchronous
Norio Kobota
 
PPTX
Reactive Programming
maruyama097
 
PDF
Introduction pp.js
Mizushima Kazuhiro
 
PPT
“なめらか”なメトロスタイルアプリを作るために ~WinRT の非同期性を活用したアプリ開発~
ShinichiAoyagi
 
PPT
Vsugday2012 summer tokyo_aoyagi
vsug_jim
 
PPTX
歌舞伎座Tech Rx会
Kaora Shibacaki
 
async/await不要論
bleis tift
 
Windows 8時代のUXを支える非同期プログラミング
Yuya Yamaki
 
これからの「async/await」の話をしよう
Kouji Matsui
 
async/await のしくみ
信之 岩永
 
C# 8.0 非同期ストリーム
信之 岩永
 
いまさら恥ずかしくてAsyncをawaitした
Kouji Matsui
 
Mono is Dead
melpon
 
Reactive Extensionsで非同期処理を簡単に
Yoshifumi Kawai
 
パターンでわかる! .NET Coreの非同期処理
Kouji Matsui
 
.NET最先端技術によるハイパフォーマンスウェブアプリケーション
Yoshifumi Kawai
 
Reactive
Akihiro Ikezoe
 
【Unite Tokyo 2018】さては非同期だなオメー!async/await完全に理解しよう
Unity Technologies Japan K.K.
 
Windows Store App HTTP通信を振り返る
Tomonori Ohba
 
トランザクションの並行処理制御
Takashi Hoshino
 
Non blocking and asynchronous
Norio Kobota
 
Reactive Programming
maruyama097
 
Introduction pp.js
Mizushima Kazuhiro
 
“なめらか”なメトロスタイルアプリを作るために ~WinRT の非同期性を活用したアプリ開発~
ShinichiAoyagi
 
Vsugday2012 summer tokyo_aoyagi
vsug_jim
 
歌舞伎座Tech Rx会
Kaora Shibacaki
 

More from Tusyoshi Matsuzaki (6)

PDF
Apache Spark on Azure
Tusyoshi Matsuzaki
 
PDF
Minecraft による強化学習の実践 (MineRL)
Tusyoshi Matsuzaki
 
PDF
Spark Analytics - スケーラブルな分散処理
Tusyoshi Matsuzaki
 
PPTX
クラウドの潮流と Windows Azure の位置づけ (エフスタ Tokyo 資料)
Tusyoshi Matsuzaki
 
PDF
アイデンティティ プロバイダーとの連携手法 Tsmatsuz
Tusyoshi Matsuzaki
 
PPTX
SharePoint 2010 を使ったクラウドアプリ開発
Tusyoshi Matsuzaki
 
Apache Spark on Azure
Tusyoshi Matsuzaki
 
Minecraft による強化学習の実践 (MineRL)
Tusyoshi Matsuzaki
 
Spark Analytics - スケーラブルな分散処理
Tusyoshi Matsuzaki
 
クラウドの潮流と Windows Azure の位置づけ (エフスタ Tokyo 資料)
Tusyoshi Matsuzaki
 
アイデンティティ プロバイダーとの連携手法 Tsmatsuz
Tusyoshi Matsuzaki
 
SharePoint 2010 を使ったクラウドアプリ開発
Tusyoshi Matsuzaki
 

Recently uploaded (9)

PDF
20250730_QiitaBash_LT登壇資料_PDC_Kurashina.pdf
pdckurashina
 
PDF
第三世代 ウェザーステーションキット v3 ー WSC3-L 日本語カタログ
CRI Japan, Inc.
 
PPTX
baserCMS『カスタムコンテンツ』徹底活用術〜あなただけの管理画面を自由自在に〜
Ryuji Egashira
 
PDF
20250729_Devin-for-Enterprise
Masaki Yamakawa
 
PDF
MahiroYoshida_セリフに着目したキャラクタロール推定に関する基礎検討_sigcc12th2025
Matsushita Laboratory
 
PDF
20250726_Devinで変えるエンプラシステム開発の未来
Masaki Yamakawa
 
PDF
【学会聴講報告】CVPR2025からみるVision最先端トレンド / CVPR2025 report
Sony - Neural Network Libraries
 
PDF
TaketoFujikawa_ComicComputing12th_inKumamoto
Matsushita Laboratory
 
PPTX
2025_7_25_吉祥寺_設計ナイト_ADR運用におけるデータ利活用の考え方.pptx
ssuserfcafd1
 
20250730_QiitaBash_LT登壇資料_PDC_Kurashina.pdf
pdckurashina
 
第三世代 ウェザーステーションキット v3 ー WSC3-L 日本語カタログ
CRI Japan, Inc.
 
baserCMS『カスタムコンテンツ』徹底活用術〜あなただけの管理画面を自由自在に〜
Ryuji Egashira
 
20250729_Devin-for-Enterprise
Masaki Yamakawa
 
MahiroYoshida_セリフに着目したキャラクタロール推定に関する基礎検討_sigcc12th2025
Matsushita Laboratory
 
20250726_Devinで変えるエンプラシステム開発の未来
Masaki Yamakawa
 
【学会聴講報告】CVPR2025からみるVision最先端トレンド / CVPR2025 report
Sony - Neural Network Libraries
 
TaketoFujikawa_ComicComputing12th_inKumamoto
Matsushita Laboratory
 
2025_7_25_吉祥寺_設計ナイト_ADR運用におけるデータ利活用の考え方.pptx
ssuserfcafd1
 

.NET Web プログラミングにおける非同期 IO のすべて (Build Insider OFFLINE)

  • 1. .NET Web プログラミングにおける 非同期 I/O のすべて 日本マイクロソフト株式会社 エバンジェリスト 松崎 剛 http://blogs.msdn.com/b/tsmatsuz
  • 2. 2 セッション ゴール • .NET Web 開発における非同期 IO の基本を学ぶ 発想の原点や歴史、基本メカニズム、用語などについて • べし・べからず、Tips、などを理解 新機能にはワケがある ! ~ スケーラブルな Web を作ろう ~
  • 3. 3 非同期のプログラミング・パターン • EAP (Event-based Asynchronous Pattern) • APM (Asynchronous Programming Model) • TAP (Task-based Asynchronous Pattern) FileStream fs; byte[] readArray = new byte[0x1000]; . . . fs.BeginRead(readArray, 0, readArray.Length, new AsyncCallback(readCallback), fs); . . . private void readCallback(IAsyncResult ar) { System.IO.FileStream fs = (System.IO.FileStream)ar.AsyncState; int fsize = fs.EndRead(ar); . . . } MyReadClass myRead = new MyReadClass(); myRead.ReadCompleted += new EventHandler<ReadCompletedEventArgs>( readCompleted); myRead.ReadAsync(); . . . private void readCompleted( object sender, ReadCompletedEventArgs e) { var res = e.Result; . . . } using (StreamReader reader = File.OpenText(filename)) { result = new char[reader.BaseStream.Length]; Task<int> t = reader.ReadAsync(result, 0, (int) reader.BaseStream.Length); }
  • 4. 4 ASP.NET における非同期の変遷 ASP.NET Web フォーム ASP.NET MVC .NET 2.0 .NET 3.5 .NET 4.5 .NET 4.0
  • 5. 5 プログラミング・パターンの相性 protected void Page_Load(object sender, EventArgs e) { if (!IsPostBack) { this.PreRenderComplete += new EventHandler(Page_PreRenderComplete); AddOnPreRenderCompleteAsync( new BeginEventHandler(BeginAsyncOperation), new EndEventHandler(EndAsyncOperation)); } } IAsyncResult BeginAsyncOperation(object sender, EventArgs e, AsyncCallback cb, object state) { _connection = new SqlConnection(connectstring); _connection.Open(); _command = new SqlCommand( "SELECT title_id, title, price FROM titles", _connection); return _command.BeginExecuteReader(cb, state); } void EndAsyncOperation(IAsyncResult ar) { _reader = _command.EndExecuteReader(ar); } protected void Page_PreRenderComplete(object sender, EventArgs e) { Output.DataSource = _reader; Output.DataBind(); } ASP.NET Async Page (APM) + DB Access (APM)
  • 6. 6 TAP + async/await (C# 5.0) public Task<ActionResult> Test1() { // Step 1 HttpClient cl = new HttpClient(); Task<HttpResponseMessage> task = cl.GetAsync(@"http://heavyweb.cloudapp.net/"); return task.ContinueWith(t => { // Step 2 ViewBag.ResultData = t.Result.ToString(); return (ActionResult)View(); }); } public async Task<ActionResult> Test1() { // Step 1 HttpClient cl = new HttpClient(); HttpResponseMessage result = await cl.GetAsync(@"http://heavyweb.cloudapp.net/"); // Step 2 ViewBag.ResultData = result.ToString(); return (ActionResult)View(); }
  • 7. 7 ASP.NET における非同期 要求 (Request)、キュー (Queue)、スレッド (Thread) Web サーバー (IIS) 要求 (Request) キュー (Queue) 処理中 … 処理中 … 処理中 … スレッド (Thread) スレッド プール
  • 14. 14 I/O Completion Port (IOCP) • Windows が提供する機構 • 1 つの IOCP は、1 つ以上のデバイス ハンドル (ファイル ハンドルな ど) と関連 • キューのメカニズムを使って、非同期 IO の完了をプログラムから検知 • スレッドの状態 (待ち状態、リリース状態、など) を監視し、スレッド の実行数を自動で制御 • IOCP でブロックされたスレッドは、いったん解放されて、LIFO の キューに入る (1 つのスレッドが継続して処理可能。可能な限り Context Switch を抑制) • Win32 API を提供 • カスタムな制御が可能 • Thread Pool API を使った I/O 処理、Timer処理 (Thread Pool Timer) で使用
  • 15. 15 15
  • 16. 16 16 public class Handler1 : IHttpHandler { public void ProcessRequest(HttpContext context) { if (context.IsWebSocketRequest) { BetsHandler1 handler = new BetsHandler1(); context.AcceptWebSocketRequest(handler.Receive); } else { context.Response.StatusCode = 400; //bad request } } . . . } public class BetsHandler1 { public WebSocket webSocket; public async Task Receive( AspNetWebSocketContext context) { webSocket = context.WebSocket; ArraySegment<byte> buf = new ArraySegment<byte>(new byte[2048]); while (true) { WebSocketReceiveResult res = await webSocket.ReceiveAsync( buf, System.Threading.CancellationToken.None); if (res.MessageType == WebSocketMessageType.Close) { // Close Message connectedHandlers.Remove(this); await webSocket.CloseOutputAsync( . . .); break; } else if (res.MessageType == WebSocketMessageType.Text) { // Text Message . . . Some kind of process } } } . . . }
  • 17. 17 17 public class Handler1 : IHttpHandler { public void ProcessRequest(HttpContext context) { if (context.IsWebSocketRequest) { BetsHandler1 handler = new BetsHandler1(); context.AcceptWebSocketRequest(handler.Receive); } else { context.Response.StatusCode = 400; //bad request } } . . . } public class BetsHandler1 { public WebSocket webSocket; public Task Receive( AspNetWebSocketContext context) { webSocket = context.WebSocket; ArraySegment<byte> buf = new ArraySegment<byte>(new byte[2048]); while (true) { WebSocketReceiveResult res = webSocket.ReceiveAsync( buf, System.Threading.CancellationToken.None); if (res.MessageType == WebSocketMessageType.Close) { // Close Message connectedHandlers.Remove(this); webSocket.CloseOutputAsync( . . .); break; } else if (res.MessageType == WebSocketMessageType.Text) { // Text Message . . . Some kind of process } } return new TaskFactory().StartNew(() => { }); } . . . }
  • 18. 18 .NET 4.5 Web の TAP 対応 (“呼ぶ” 側) • ASP.NET Web フォーム • ASP.NET Web API • WCF • WebSocket . . . protected void Page_Load(object sender, EventArgs e) { Page.RegisterAsyncTask(new PageAsyncTask(async () => { HttpClient cl = new HttpClient(); HttpResponseMessage res = await cl.GetAsync(@“http://.../"); Label1.Text = res.ToString(); })); } public class Service1 : IService1 { public async Task<string> GetDataAsync() { HttpClient cl = new HttpClient(); HttpResponseMessage res = await cl.GetAsync(@“http://.../"); return res.ToString(); } } public class ValuesController : ApiController { // GET api/values public async Task<string> Get() { HttpClient cl = new HttpClient(); HttpResponseMessage res = await cl.GetAsync(@"http://.../"); return res.ToString(); } } context.AcceptWebSocketRequest(handler.Receive); . . . public async Task Receive(AspNetWebSocketContext context) { while (true) { WebSocketReceiveResult res = await context.WebSocket.ReceiveAsync(. . .); . . . } }
  • 19. 19 IO リソースの TAP 対応 (“呼ばれる” 側) ファイル入出力 .NET 4.5 で TAP (async) のメソッド (ReadAsync, WriteAsync, CopyToAsync など) を提供 (これまでは、APM のみ) データ ベース ADO.NET .NET 4.5 で TAP (async) のメソッド (ReadAsync など) を提供 (これまでは、APM のみ) Entity Framework Entity Framework 6 で、TAP (async) をサポート (現在、ベータ版を提供) ネット ワーク REST HttpClient のメソッドは、基本的に TAP ベース WCF .NET 4.5 で自動生成される Service Refrence Proxy では、TAP (async) のメソッドを提供 クラウド Windows Azure ServiceBus 最新の WindowsAzure.ServiceBus パッケージ (NuGet) で TAP の メソッド (NamespaceManager.QueueExistsAsync など) を提供 (APM も使用可能) では、未対応のものはどうする ? (例 : WCF Data Services, Windows Azure Storage など) ますます、対応中 . . . (こうご期待!)
  • 20. 20 SynchronizationContext • スレッド間の関係を管理する抽象化されたスケジューラー・オブジェクト  ASP.NET 非同期スレッドは、Win32 メッセージ ループのように特定スレッドに紐づかない • 1 つのスレッドに対し、必ず 1 つの SynchronizationContext が存在 (ただし、単一 のSynchronizationContext は複数スレッドで共有) • 一部の実装 (override メソッド) を除き、具体的な実装は派生クラスに依存  WindowsFormsSynchronizationContext  DispatcherSynchronizationContext  AspNetSynchronizationContext  既定の SynchronizationContext • これまでの非同期処理 (EAP など) において、その動作をつかさどる • TAP では TaskScheduler を使用 (SynchronizationContext を使用する際は、 TaskScheduler.FromCurrentSynchronizationContext を明示)
  • 21. 21 SynchronizationContext • 既定の Awaiter (TaskAwaiter) は、Current の SynchronizationContext を使用 (なければ TaskScheduler も参照)  AspNetSynchronizationContext では、同期ブロックに入れるスレッドは 1 つだけ • .NET 4 以降では、Task と相性の良い新しい AspNetSynchronizationContext を使用  従来のものは LegacyAspNetSynchronizationContext に変更 この場合でも、Web.configの設定で新しいContextを 使用可能 <appSettings> <add key="aspnet:UseTaskFriendlySynchronizationContext“ value="true"/> </appSettings>
  • 22. 22 混ぜるな、危険 💀 • Async (EAP, TAP, etc) と Sync の混 在プログラムは、デッドロックの原因 となる ! Task で受け取った内容を、むりやり同期 化しない (All async is beautiful !) 「扱いやすい」(理解しやすい) という理 由だけで、 Result、Wait を多用しない (初心者にありがちなミス) 現実の開発では、追跡とデバッグが非常に 困難 (例 : 単一では動作するんだけ ど ?、コンソール・アプリでは動くのに ? など)