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
PPTX
そうだったのか! よくわかる process.nextTick() node.jsのイベントループを理解する
PPTX
async/await のしくみ
PPTX
9/14にリリースされたばかりの新LTS版Java 17、ここ3年間のJavaの変化を知ろう!(Open Source Conference 2021 O...
PDF
Mavenの真実とウソ
ODP
SPAのルーティングの話
PDF
PostgreSQLアーキテクチャ入門
PDF
ソフトウェア設計における 意思決定とそのレビューの秘訣
An other world awaits you
そうだったのか! よくわかる process.nextTick() node.jsのイベントループを理解する
async/await のしくみ
9/14にリリースされたばかりの新LTS版Java 17、ここ3年間のJavaの変化を知ろう!(Open Source Conference 2021 O...
Mavenの真実とウソ
SPAのルーティングの話
PostgreSQLアーキテクチャ入門
ソフトウェア設計における 意思決定とそのレビューの秘訣

What's hot (20)

PPTX
このPHP QAツールがすごい!2019
PDF
【プライム・ストラテジー】ローカルLLMを複数組み合わてみた(インフラエンジニアのためのChatGPT入門LT)
PDF
MySQLを割と一人で300台管理する技術
PPTX
Msを16倍出し抜くwpf開発2回目
PDF
SQLアンチパターン 幻の第26章「とりあえず削除フラグ」
PDF
意識の低い自動化
PDF
より速く より運用しやすく 進化し続けるJVM(Java Developers Summit Online 2023 発表資料)
PDF
Map Reduce 〜入門編:仕組みの理解とアルゴリズムデザイン〜
PPTX
10分でわかるOpenAPI V3
PDF
Introduction httpClient on Java11 / Java11時代のHTTPアクセス再入門
PDF
いまさら恥ずかしくてAsyncをawaitした
PDF
「再代入なんて、あるわけない」 ~ふつうのプログラマが関数型言語を知るべき理由~ (Gunma.web #5 2011/05/14)
PPTX
フリーでできるセキュリティWeb編(SQLMあpを楽しもう)
PPTX
PSR-1 と PSR-2 を 5分でざっくり理解する
PPTX
Net 6 的 blazor 開發新視界
PDF
NVIDIA GPUで作るHeadless X11 Linux
ODP
Goのサーバサイド実装におけるレイヤ設計とレイヤ内実装について考える
PPTX
C# 9.0 / .NET 5.0
PPTX
非同期処理の基礎
PPTX
C#で速度を極めるいろは
このPHP QAツールがすごい!2019
【プライム・ストラテジー】ローカルLLMを複数組み合わてみた(インフラエンジニアのためのChatGPT入門LT)
MySQLを割と一人で300台管理する技術
Msを16倍出し抜くwpf開発2回目
SQLアンチパターン 幻の第26章「とりあえず削除フラグ」
意識の低い自動化
より速く より運用しやすく 進化し続けるJVM(Java Developers Summit Online 2023 発表資料)
Map Reduce 〜入門編:仕組みの理解とアルゴリズムデザイン〜
10分でわかるOpenAPI V3
Introduction httpClient on Java11 / Java11時代のHTTPアクセス再入門
いまさら恥ずかしくてAsyncをawaitした
「再代入なんて、あるわけない」 ~ふつうのプログラマが関数型言語を知るべき理由~ (Gunma.web #5 2011/05/14)
フリーでできるセキュリティWeb編(SQLMあpを楽しもう)
PSR-1 と PSR-2 を 5分でざっくり理解する
Net 6 的 blazor 開發新視界
NVIDIA GPUで作るHeadless X11 Linux
Goのサーバサイド実装におけるレイヤ設計とレイヤ内実装について考える
C# 9.0 / .NET 5.0
非同期処理の基礎
C#で速度を極めるいろは
Ad

Viewers also liked (9)

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

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

PDF
Javaセキュアコーディングセミナー東京第3回講義
PDF
Em synchrony について
PDF
OpenStack + Common Lisp
PPTX
HTML5&API総まくり
PDF
Reactive Extensionsで非同期処理を簡単に
PPTX
イベント駆動プログラミングとI/O多重化
PPT
20010901
PDF
CEDEC 2018 最速のC#の書き方 - C#大統一理論へ向けて性能的課題を払拭する
PDF
OSvの概要と実装
PPTX
Terraformで始めるInfrastructure as Code
PPTX
Web API(Dynamics 365 )勉強会
PDF
Lightweight-Stream-APIのあるAndroidアプリ開発
PDF
20121217 jawsug-yokohama
PPTX
複数アプリケーションの プロセスとログを管理する ための新しいツールと手法
PDF
Node.jsでブラウザメッセンジャー
PDF
東京Node学園#3 Domains & Isolates
PDF
Cookpad Summer Intern 2015 - Programming Paradigm
PDF
Ext.directことはじめ
PDF
SlackのIncomingWebhooksとOutgoingWebhooksを使って電子工作と連携させてみよう
PDF
Node-v0.12の新機能について
Javaセキュアコーディングセミナー東京第3回講義
Em synchrony について
OpenStack + Common Lisp
HTML5&API総まくり
Reactive Extensionsで非同期処理を簡単に
イベント駆動プログラミングとI/O多重化
20010901
CEDEC 2018 最速のC#の書き方 - C#大統一理論へ向けて性能的課題を払拭する
OSvの概要と実装
Terraformで始めるInfrastructure as Code
Web API(Dynamics 365 )勉強会
Lightweight-Stream-APIのあるAndroidアプリ開発
20121217 jawsug-yokohama
複数アプリケーションの プロセスとログを管理する ための新しいツールと手法
Node.jsでブラウザメッセンジャー
東京Node学園#3 Domains & Isolates
Cookpad Summer Intern 2015 - Programming Paradigm
Ext.directことはじめ
SlackのIncomingWebhooksとOutgoingWebhooksを使って電子工作と連携させてみよう
Node-v0.12の新機能について

More from Tusyoshi Matsuzaki (6)

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

.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 を多用しない (初心者にありがちなミス) 現実の開発では、追跡とデバッグが非常に 困難 (例 : 単一では動作するんだけ ど ?、コンソール・アプリでは動くのに ? など)