Enviar búsqueda
Cargar
Mono is Dead
•
57 recomendaciones
•
17,671 vistas
M
melpon
Seguir
Monoは死んだ
Leer menos
Leer más
Tecnología
Denunciar
Compartir
Denunciar
Compartir
1 de 104
Descargar ahora
Descargar para leer sin conexión
Recomendados
ZeroFormatterに見るC#で最速のシリアライザを作成する100億の方法
ZeroFormatterに見るC#で最速のシリアライザを作成する100億の方法
Yoshifumi Kawai
ZeroFormatter/MagicOnion - Fastest C# Serializer/gRPC based C# RPC
ZeroFormatter/MagicOnion - Fastest C# Serializer/gRPC based C# RPC
Yoshifumi Kawai
RuntimeUnitTestToolkit for Unity
RuntimeUnitTestToolkit for Unity
Yoshifumi Kawai
CEDEC 2018 最速のC#の書き方 - C#大統一理論へ向けて性能的課題を払拭する
CEDEC 2018 最速のC#の書き方 - C#大統一理論へ向けて性能的課題を払拭する
Yoshifumi Kawai
Inside FastEnum
Inside FastEnum
Takaaki Suzuki
Hello Dark-Side C# (Part. 1)
Hello Dark-Side C# (Part. 1)
Yuto Takei
【Unite Tokyo 2019】Understanding C# Struct All Things
【Unite Tokyo 2019】Understanding C# Struct All Things
UnityTechnologiesJapan002
Lisp Tutorial for Pythonista Day 6
Lisp Tutorial for Pythonista Day 6
Ransui Iso
Recomendados
ZeroFormatterに見るC#で最速のシリアライザを作成する100億の方法
ZeroFormatterに見るC#で最速のシリアライザを作成する100億の方法
Yoshifumi Kawai
ZeroFormatter/MagicOnion - Fastest C# Serializer/gRPC based C# RPC
ZeroFormatter/MagicOnion - Fastest C# Serializer/gRPC based C# RPC
Yoshifumi Kawai
RuntimeUnitTestToolkit for Unity
RuntimeUnitTestToolkit for Unity
Yoshifumi Kawai
CEDEC 2018 最速のC#の書き方 - C#大統一理論へ向けて性能的課題を払拭する
CEDEC 2018 最速のC#の書き方 - C#大統一理論へ向けて性能的課題を払拭する
Yoshifumi Kawai
Inside FastEnum
Inside FastEnum
Takaaki Suzuki
Hello Dark-Side C# (Part. 1)
Hello Dark-Side C# (Part. 1)
Yuto Takei
【Unite Tokyo 2019】Understanding C# Struct All Things
【Unite Tokyo 2019】Understanding C# Struct All Things
UnityTechnologiesJapan002
Lisp Tutorial for Pythonista Day 6
Lisp Tutorial for Pythonista Day 6
Ransui Iso
NextGen Server/Client Architecture - gRPC + Unity + C#
NextGen Server/Client Architecture - gRPC + Unity + C#
Yoshifumi Kawai
XML-RPC : Pythonが「電池付属」と呼ばれる理由
XML-RPC : Pythonが「電池付属」と呼ばれる理由
Ransui Iso
Introduction to cython
Introduction to cython
Atsuo Ishimoto
async/await のしくみ
async/await のしくみ
信之 岩永
Pyconjp2014_implementations
Pyconjp2014_implementations
masahitojp
Async design with Unity3D
Async design with Unity3D
Kouji Hosoda
Altanative macro
Altanative macro
Motohiro KOSAKI
LINQ in Unity
LINQ in Unity
Yoshifumi Kawai
PyOpenCLによるGPGPU入門
PyOpenCLによるGPGPU入門
Yosuke Onoue
「黒騎士と白の魔王」gRPCによるHTTP/2 - API, Streamingの実践
「黒騎士と白の魔王」gRPCによるHTTP/2 - API, Streamingの実践
Yoshifumi Kawai
本当にわかる Spectre と Meltdown
本当にわかる Spectre と Meltdown
Hirotaka Kawata
Python 3.6 リリースパーティー 発表資料
Python 3.6 リリースパーティー 発表資料
Atsuo Ishimoto
llvm入門
llvm入門
MITSUNARI Shigeo
core dumpでcode golf
core dumpでcode golf
Nomura Yusuke
A quick tour of the Cysharp OSS
A quick tour of the Cysharp OSS
Yoshifumi Kawai
Effective Modern C++ 勉強会#3 Item16
Effective Modern C++ 勉強会#3 Item16
Mitsuru Kariya
高速な倍精度指数関数expの実装
高速な倍精度指数関数expの実装
MITSUNARI Shigeo
effective modern c++ chapeter36
effective modern c++ chapeter36
Tatsuki SHIMIZU
SEH on mingw32
SEH on mingw32
kikairoya
高速な暗号実装のためにしてきたこと
高速な暗号実装のためにしてきたこと
MITSUNARI Shigeo
CrystalFantasiaを支えきった技術と技術だけではどうにもならなかった話
CrystalFantasiaを支えきった技術と技術だけではどうにもならなかった話
Keisuke Utsumi
HttpClient詳解、或いは非同期の落とし穴について
HttpClient詳解、或いは非同期の落とし穴について
Yoshifumi Kawai
Más contenido relacionado
La actualidad más candente
NextGen Server/Client Architecture - gRPC + Unity + C#
NextGen Server/Client Architecture - gRPC + Unity + C#
Yoshifumi Kawai
XML-RPC : Pythonが「電池付属」と呼ばれる理由
XML-RPC : Pythonが「電池付属」と呼ばれる理由
Ransui Iso
Introduction to cython
Introduction to cython
Atsuo Ishimoto
async/await のしくみ
async/await のしくみ
信之 岩永
Pyconjp2014_implementations
Pyconjp2014_implementations
masahitojp
Async design with Unity3D
Async design with Unity3D
Kouji Hosoda
Altanative macro
Altanative macro
Motohiro KOSAKI
LINQ in Unity
LINQ in Unity
Yoshifumi Kawai
PyOpenCLによるGPGPU入門
PyOpenCLによるGPGPU入門
Yosuke Onoue
「黒騎士と白の魔王」gRPCによるHTTP/2 - API, Streamingの実践
「黒騎士と白の魔王」gRPCによるHTTP/2 - API, Streamingの実践
Yoshifumi Kawai
本当にわかる Spectre と Meltdown
本当にわかる Spectre と Meltdown
Hirotaka Kawata
Python 3.6 リリースパーティー 発表資料
Python 3.6 リリースパーティー 発表資料
Atsuo Ishimoto
llvm入門
llvm入門
MITSUNARI Shigeo
core dumpでcode golf
core dumpでcode golf
Nomura Yusuke
A quick tour of the Cysharp OSS
A quick tour of the Cysharp OSS
Yoshifumi Kawai
Effective Modern C++ 勉強会#3 Item16
Effective Modern C++ 勉強会#3 Item16
Mitsuru Kariya
高速な倍精度指数関数expの実装
高速な倍精度指数関数expの実装
MITSUNARI Shigeo
effective modern c++ chapeter36
effective modern c++ chapeter36
Tatsuki SHIMIZU
SEH on mingw32
SEH on mingw32
kikairoya
高速な暗号実装のためにしてきたこと
高速な暗号実装のためにしてきたこと
MITSUNARI Shigeo
La actualidad más candente
(20)
NextGen Server/Client Architecture - gRPC + Unity + C#
NextGen Server/Client Architecture - gRPC + Unity + C#
XML-RPC : Pythonが「電池付属」と呼ばれる理由
XML-RPC : Pythonが「電池付属」と呼ばれる理由
Introduction to cython
Introduction to cython
async/await のしくみ
async/await のしくみ
Pyconjp2014_implementations
Pyconjp2014_implementations
Async design with Unity3D
Async design with Unity3D
Altanative macro
Altanative macro
LINQ in Unity
LINQ in Unity
PyOpenCLによるGPGPU入門
PyOpenCLによるGPGPU入門
「黒騎士と白の魔王」gRPCによるHTTP/2 - API, Streamingの実践
「黒騎士と白の魔王」gRPCによるHTTP/2 - API, Streamingの実践
本当にわかる Spectre と Meltdown
本当にわかる Spectre と Meltdown
Python 3.6 リリースパーティー 発表資料
Python 3.6 リリースパーティー 発表資料
llvm入門
llvm入門
core dumpでcode golf
core dumpでcode golf
A quick tour of the Cysharp OSS
A quick tour of the Cysharp OSS
Effective Modern C++ 勉強会#3 Item16
Effective Modern C++ 勉強会#3 Item16
高速な倍精度指数関数expの実装
高速な倍精度指数関数expの実装
effective modern c++ chapeter36
effective modern c++ chapeter36
SEH on mingw32
SEH on mingw32
高速な暗号実装のためにしてきたこと
高速な暗号実装のためにしてきたこと
Destacado
CrystalFantasiaを支えきった技術と技術だけではどうにもならなかった話
CrystalFantasiaを支えきった技術と技術だけではどうにもならなかった話
Keisuke Utsumi
HttpClient詳解、或いは非同期の落とし穴について
HttpClient詳解、或いは非同期の落とし穴について
Yoshifumi Kawai
Async deepdive before de:code
Async deepdive before de:code
Kouji Matsui
continuatioN Linking
continuatioN Linking
Kouji Matsui
Async await in C++
Async await in C++
cppfrug
これからの「async/await」の話をしよう
これからの「async/await」の話をしよう
Kouji Matsui
async/awaitダークサイド is 何
async/awaitダークサイド is 何
Kouji Matsui
async/await不要論
async/await不要論
bleis tift
Destacado
(8)
CrystalFantasiaを支えきった技術と技術だけではどうにもならなかった話
CrystalFantasiaを支えきった技術と技術だけではどうにもならなかった話
HttpClient詳解、或いは非同期の落とし穴について
HttpClient詳解、或いは非同期の落とし穴について
Async deepdive before de:code
Async deepdive before de:code
continuatioN Linking
continuatioN Linking
Async await in C++
Async await in C++
これからの「async/await」の話をしよう
これからの「async/await」の話をしよう
async/awaitダークサイド is 何
async/awaitダークサイド is 何
async/await不要論
async/await不要論
Similar a Mono is Dead
C# 7.2 with .NET Core 2.1
C# 7.2 with .NET Core 2.1
信之 岩永
「Python言語」はじめの一歩 / First step of Python / 2016 Jan 12
「Python言語」はじめの一歩 / First step of Python / 2016 Jan 12
Takanori Suzuki
Gpgpu tomoaki-fp16
Gpgpu tomoaki-fp16
tomoaki0705
Bossan dentoo
Bossan dentoo
kubo39
Richard high performance fuzzing ja
Richard high performance fuzzing ja
PacSecJP
ゆるふわLinux-HA 〜PostgreSQL編〜
ゆるふわLinux-HA 〜PostgreSQL編〜
Taro Matsuzawa
密着!わたしのコンソールアプリ開発環境
密着!わたしのコンソールアプリ開発環境
Fumihito Yokoyama
Firefox 3.1 & MozTech
Firefox 3.1 & MozTech
dynamis
C# 8.0 Preview in Visual Studio 2019 (16.0)
C# 8.0 Preview in Visual Studio 2019 (16.0)
信之 岩永
.NET Core 2.x 時代の C#
.NET Core 2.x 時代の C#
信之 岩永
Buffer overflow
Buffer overflow
ionis111
Stream2の基本
Stream2の基本
shigeki_ohtsu
WebRTC SFU mediasoup sample
WebRTC SFU mediasoup sample
mganeko
SmartNews TechNight Vol5 : SmartNews AdServer 解体新書 / ポストモーテム
SmartNews TechNight Vol5 : SmartNews AdServer 解体新書 / ポストモーテム
SmartNews, Inc.
ネットワーク ゲームにおけるTCPとUDPの使い分け
ネットワーク ゲームにおけるTCPとUDPの使い分け
モノビット エンジン
ネットワーク ゲームにおけるTCPとUDPの使い分け
ネットワーク ゲームにおけるTCPとUDPの使い分け
モノビット エンジン
Firefox 3.1 In Depth (?)
Firefox 3.1 In Depth (?)
dynamis
C# 8.0 非同期ストリーム
C# 8.0 非同期ストリーム
信之 岩永
clu2cは64ビットOSでも使えます (OSC 2012 Hiroshima LT用資料)
clu2cは64ビットOSでも使えます (OSC 2012 Hiroshima LT用資料)
洋史 東平
Ossで作成するチーム開発環境
Ossで作成するチーム開発環境
Tadahiro Ishisaka
Similar a Mono is Dead
(20)
C# 7.2 with .NET Core 2.1
C# 7.2 with .NET Core 2.1
「Python言語」はじめの一歩 / First step of Python / 2016 Jan 12
「Python言語」はじめの一歩 / First step of Python / 2016 Jan 12
Gpgpu tomoaki-fp16
Gpgpu tomoaki-fp16
Bossan dentoo
Bossan dentoo
Richard high performance fuzzing ja
Richard high performance fuzzing ja
ゆるふわLinux-HA 〜PostgreSQL編〜
ゆるふわLinux-HA 〜PostgreSQL編〜
密着!わたしのコンソールアプリ開発環境
密着!わたしのコンソールアプリ開発環境
Firefox 3.1 & MozTech
Firefox 3.1 & MozTech
C# 8.0 Preview in Visual Studio 2019 (16.0)
C# 8.0 Preview in Visual Studio 2019 (16.0)
.NET Core 2.x 時代の C#
.NET Core 2.x 時代の C#
Buffer overflow
Buffer overflow
Stream2の基本
Stream2の基本
WebRTC SFU mediasoup sample
WebRTC SFU mediasoup sample
SmartNews TechNight Vol5 : SmartNews AdServer 解体新書 / ポストモーテム
SmartNews TechNight Vol5 : SmartNews AdServer 解体新書 / ポストモーテム
ネットワーク ゲームにおけるTCPとUDPの使い分け
ネットワーク ゲームにおけるTCPとUDPの使い分け
ネットワーク ゲームにおけるTCPとUDPの使い分け
ネットワーク ゲームにおけるTCPとUDPの使い分け
Firefox 3.1 In Depth (?)
Firefox 3.1 In Depth (?)
C# 8.0 非同期ストリーム
C# 8.0 非同期ストリーム
clu2cは64ビットOSでも使えます (OSC 2012 Hiroshima LT用資料)
clu2cは64ビットOSでも使えます (OSC 2012 Hiroshima LT用資料)
Ossで作成するチーム開発環境
Ossで作成するチーム開発環境
Último
SOPを理解する 2024/04/19 の勉強会で発表されたものです
SOPを理解する 2024/04/19 の勉強会で発表されたものです
iPride Co., Ltd.
論文紹介:Content-Aware Token Sharing for Efficient Semantic Segmentation With Vis...
論文紹介:Content-Aware Token Sharing for Efficient Semantic Segmentation With Vis...
Toru Tamaki
論文紹介:Semantic segmentation using Vision Transformers: A survey
論文紹介:Semantic segmentation using Vision Transformers: A survey
Toru Tamaki
Postman LT Fukuoka_Quick Prototype_By Daniel
Postman LT Fukuoka_Quick Prototype_By Daniel
danielhu54
TSAL operation mechanism and circuit diagram.pdf
TSAL operation mechanism and circuit diagram.pdf
taisei2219
スマートフォンを用いた新生児あやし動作の教示システム
スマートフォンを用いた新生児あやし動作の教示システム
sugiuralab
[DevOpsDays Tokyo 2024] 〜デジタルとアナログのはざまに〜 スマートビルディング爆速開発を支える 自動化テスト戦略
[DevOpsDays Tokyo 2024] 〜デジタルとアナログのはざまに〜 スマートビルディング爆速開発を支える 自動化テスト戦略
Ryo Sasaki
論文紹介:Automated Classification of Model Errors on ImageNet
論文紹介:Automated Classification of Model Errors on ImageNet
Toru Tamaki
Open Source UN-Conference 2024 Kawagoe - 独自OS「DaisyOS GB」の紹介
Open Source UN-Conference 2024 Kawagoe - 独自OS「DaisyOS GB」の紹介
Yuma Ohgami
Último
(9)
SOPを理解する 2024/04/19 の勉強会で発表されたものです
SOPを理解する 2024/04/19 の勉強会で発表されたものです
論文紹介:Content-Aware Token Sharing for Efficient Semantic Segmentation With Vis...
論文紹介:Content-Aware Token Sharing for Efficient Semantic Segmentation With Vis...
論文紹介:Semantic segmentation using Vision Transformers: A survey
論文紹介:Semantic segmentation using Vision Transformers: A survey
Postman LT Fukuoka_Quick Prototype_By Daniel
Postman LT Fukuoka_Quick Prototype_By Daniel
TSAL operation mechanism and circuit diagram.pdf
TSAL operation mechanism and circuit diagram.pdf
スマートフォンを用いた新生児あやし動作の教示システム
スマートフォンを用いた新生児あやし動作の教示システム
[DevOpsDays Tokyo 2024] 〜デジタルとアナログのはざまに〜 スマートビルディング爆速開発を支える 自動化テスト戦略
[DevOpsDays Tokyo 2024] 〜デジタルとアナログのはざまに〜 スマートビルディング爆速開発を支える 自動化テスト戦略
論文紹介:Automated Classification of Model Errors on ImageNet
論文紹介:Automated Classification of Model Errors on ImageNet
Open Source UN-Conference 2024 Kawagoe - 独自OS「DaisyOS GB」の紹介
Open Source UN-Conference 2024 Kawagoe - 独自OS「DaisyOS GB」の紹介
Mono is Dead
1.
Mono is Dead ∼高速なC#サーバを目指して∼
2.
もくじ • Introduction • C#で1万Clientを捌く •
Mono is Dead
3.
Introduction
4.
やったこと • 1対1で対戦する • TCPの •
ゲームサーバを • C#(Mono)で作った
5.
結果 • 1サーバあたり10,000クライアント程度 ならいける • 無事iOSとAndroidにリリースして、ちゃ んと動いてる
6.
長く苦しい戦いだった… • 苦しかったのは主にMonoのせい • 今日はMonoをdisります •
が、その前に前提知識(async/await構 文)の共有をします
7.
Q&A • なんでC#なの? • クライアントがC#(Unity)で書かれて いて、一部のロジックを共有したかっ た
8.
Q&A • P2Pでやらないのはなぜ? • 改ざんに対する処置がゲームサーバ作 るよりめんどそう
9.
Q&A • .NET Framework使わないの? •
Windowsを運用するのはとてもつらい
10.
Q&A • なんでTCPなの?UDPじゃだめなの? • UDPはつらい •
パケット組み立てるのつらい • 再送信処理を実装するのつらい • 送信元を識別するのつらい • 切断検知つらい
11.
C#で1万Clientを捌く
12.
C#でTCP通信 • お題: 5バイトのデータを受け取り、そ のデータをそのまま返すサーバを作ろ う •
つまり劣化版Echoサーバ
13.
同期版 TcpClient client =
// Accept部分は省略 Stream stream = client.GetStream(); while (true) { var buf = new buf[5]; stream.Read(buf, 0, buf.Length); stream.Write(buf, 0, buf.Length); }
14.
ダメ • Readでbuf.Lengthだけ読める保証は無い • Readの戻り値が0の時は終端だったりエ ラーの場合なので例外を投げる •
例外の処理をしよう
15.
同期版(改) static void ReadFully(this
Stream stream, byte[] buf) { var readBytes = 0; while (readBytes != buf.Length) { var n = stream.Read(buf, readBytes, buf.Length - readBytes); if (n == 0) throw new Exception("hoge-"); readBytes += n; } }
16.
同期版(改) try { while (true)
{ var buf = new buf[5]; stream.ReadFully(buf); stream.Write(buf, 0, buf.Length); } } catch (Exception e) { // 例外出たらログを残して接続を閉じる logger.Error("error", e); client.Close(); }
17.
簡単 • 同期的に書くのはとても簡単 • 例外処理を含めても簡単
18.
だがしかし
19.
だがしかし CPUが全く働いてない
20.
だがしかし • 呼び出したスレッドが止まる • 8スレッドで動かした場合、8クライアントが Readするだけで全部止まる •
たかだかスレッド数までしかクライアントを 捌けない
21.
スレッド増やせば? • メモリが足りない • スタック領域だけで最低256KBぐらい •
コンテキストスイッチで時間が掛かる • なので1万クライアントをスレッドで捌くのは きつい • いわゆるC10K問題
22.
つまり • 1万クライアントをスレッドで同期処 理するのは無理
23.
そこで • 非同期処理 • C#には非同期処理用の関数がある •
BeginRead, EndRead, BeginWrite, EndWrite • これを使えば解決できるはず
24.
同期版(再掲) try { while (true)
{ var buf = new buf[5]; stream.ReadFully(buf); stream.Write(buf, 0, buf.Length); } } catch (Exception e) { // 例外出たらログを残して接続を閉じる logger.Error("error", e); client.Close(); }
25.
非同期版 var buf =
new byte[5]; Func<IAsyncResult> func; func = ar1 => { stream.EndReadFully(ar1); stream.BeginWrite(buf, 0, buf.Length, ar2 => { stream.EndWrite(ar2); // 再度BeginReadを始める(whileループ相当) stream.BeginReadFully(buf, 0, buf.Length, func, null); }; }; stream.BeginReadFully(buf, 0, buf.Length, func, null); 完全に別コード
26.
非同期版 var buf =
new byte[5]; Func<IAsyncResult> func; func = ar1 => { stream.EndReadFully(ar1); stream.BeginWrite(buf, 0, buf.Length, ar2 => { stream.EndWrite(ar2); // 再度BeginReadを始める(whileループ相当) stream.BeginReadFully(buf, 0, buf.Length, func, null); }; }; stream.BeginReadFully(buf, 0, buf.Length, func, null); どうやって実装するのか分かりませんでした
27.
非同期版 var buf =
new byte[5]; Func<IAsyncResult> func; func = ar1 => { stream.EndReadFully(ar1); // 例外処理どうしよう stream.BeginWrite(buf, 0, buf.Length, ar2 => { stream.EndWrite(ar2); // 例外処理どうしよう // 再度BeginReadを始める(whileループ相当) stream.BeginReadFully(buf, 0, buf.Length, func, null); }; }; stream.BeginReadFully(buf, 0, buf.Length, func, null); 例外処理つらい
28.
非同期版 var buf =
new byte[5]; Func<IAsyncResult> func; func = ar1 => { stream.EndReadFully(ar1); stream.BeginWrite(buf, 0, buf.Length, ar2 => { stream.EndWrite(ar2); // 再度BeginReadを始める(whileループ相当) stream.BeginReadFully(buf, 0, buf.Length, func, null); }; }; stream.BeginReadFully(buf, 0, buf.Length, func, null); whileループすら再帰とか…
29.
結論 • 非同期処理はつらい
30.
そこで • async/await構文 • C#
5.0 で入った新しい非同期処理
31.
同期版(再掲) static void ReadFully( this
Stream stream, byte[] buf) { var readBytes = 0; while (readBytes != buf.Length) { var n = stream.Read(buf, readBytes, buf.Length - readBytes); if (n == 0) throw new Exception("hoge-"); readBytes += n; } }
32.
async/await版 static async Task
ReadFullyAsync( this Stream stream, byte[] buf) { var readBytes = 0; while (readBytes != buf.Length) { var n = await stream.ReadAsync(buf, readBytes, buf.Length - readBytes) .ConfigureAwait(false); if (n == 0) throw new Exception("hoge-"); readBytes += n; }; }
33.
差分 static async Task
ReadFullyAsync( this Stream stream, byte[] buf) { var readBytes = 0; while (readBytes != buf.Length) { var n = await stream.ReadAsync(buf, readBytes, buf.Length - readBytes) .ConfigureAwait(false); if (n == 0) throw new Exception("hoge-"); readBytes += n; }; }
34.
同期版(再掲) try { while (true)
{ var buf = new buf[5]; stream.ReadFully(buf); stream.Write(buf, 0, buf.Length); } } catch (Exception e) { // 例外出たらログを残して接続を閉じる logger.Error("error", e); client.Close(); }
35.
async/await版 try { while (true)
{ var buf = new buf[5]; await stream.ReadFullyAsync(buf) .ConfigureAwait(false); await stream.WriteAsync(buf, 0, buf.Length) .ConfigureAwait(false); } } catch (Exception e) { // 例外出たらログを残して接続を閉じる logger.Error("error", e); client.Close(); }
36.
差分 try { while (true)
{ var buf = new buf[5]; await stream.ReadFullyAsync(buf) .ConfigureAwait(false); await stream.WriteAsync(buf, 0, buf.Length) .ConfigureAwait(false); } } catch (Exception e) { // 例外出たらログを残して接続を閉じる logger.Error("error", e); client.Close(); }
37.
async/awaitは良い • 同期版とほぼ同じように書ける • 例外処理も簡単に書ける
38.
実際の動き • スレッドの代わりにタスクと呼ばれる 単位で動作する • タスク自体はメモリをほぼ使わない •
いわゆる軽量スレッド • awaitする度にタスクを処理するスレッ ドが変わる
39.
実際の動き try { while (true)
{ var buf = new buf[5]; await stream.ReadFullyAsync(buf) .ConfigureAwait(false); await stream.WriteAsync(buf, 0, buf.Length) .ConfigureAwait(false); } } catch (Exception e) { // 例外出たらログを残して接続を閉じる logger.Error("error", e); client.Close(); } Thread1 Thread2
40.
実際の動き
41.
実際の動き タスク9個の場合
42.
Q&A • ConfigureAwait(false)って何? • これが無いと、完了通知先が必ず呼 び出し元のスレッドになる •
UI処理する場合は便利だけど、ス レッド待ちで遅くなるし、デッドロッ クが起きる可能性もある
43.
async/awaitは良い • 同期版とほぼ同じように書ける • 例外処理も簡単に書ける •
メモリをほとんど使わない (new!) • CPUを使いきれる (new!) • つまり1万クライアント捌ける
44.
async/awaitまとめ • async/awaitを使って • 高速で •
書きやすい • C#サーバ • これは…いける!
45.
async/awaitまとめ
46.
Mono is Dead ∼本編始まるよ!∼
47.
.NET is Alive •
MicrosoftVisual C#を使って実装 • VC#を使っている時点ではほぼ問題な く実装できてた
48.
Mono is Dead •
VC#ではうまく動いていたexeをMonoで 実行すると…
49.
Mono is Dead •
VC#ではうまく動いていたexeをMonoで 実行すると… _人人人人人人_ > 突然の死 <  ̄Y^Y^Y^Y^Y ̄
50.
LogicalSetData で死ぬ
51.
LogicalSetData で死ぬ • System.Runtime.Remoting.Messaging.CallC ontext.LogicalSetData •
TLS(Thread Local Storage)のタスク版み たいなやつ(正確には違うけど) • タスク単位のグローバル変数っぽいの を作りたい場合、これに頼るしか無い (はず)
52.
LogicalSetData で死ぬ • VC#では問題なく動いていたのに、 Monoだとおかしな動作をする •
Monoのソースコードを眺めてみると…
53.
LogicalSetData で死ぬ [ThreadStatic] static
Hashtable logicalDatastore; static void LogicalSetData(string name, object data) { var r = logicalDatastore; if (r == null) r = logicalDatastore = new Hashtable(); r[name] = data; } Mono-3.2.8のソースより
54.
LogicalSetData で死ぬ [ThreadStatic] static
Hashtable logicalDatastore; static void LogicalSetData(string name, object data) { var r = logicalDatastore; if (r == null) r = logicalDatastore = new Hashtable(); r[name] = data; } ただのTLS実装になっている そんな実装で大丈夫か? Mono-3.2.8のソースより
55.
LogicalSetData で死ぬ • Issueにも報告さ れている •
Mono 4.0以降で 直っていること が分かった
56.
LogicalSetData で死ぬ • タスク単位のグローバル変数を使う場 合はMono
4.0以降が必須 • Mono 4.0は2015年5月4日にリリース • 公式パッケージに入ってない可能性が あるので気をつけよう
57.
LogicalSetData で死ぬ • 結論:
Mono 3.x は死ぬべき
58.
キャンセルトークンで死ぬ
59.
キャンセルトークンで死ぬ • ReadAsyncやWriteAsyncなどの非同期処 理を中断する機能 • 主にタイムアウトの為に使う
60.
キャンセルトークンで死ぬ public virtual Task<int>
ReadAsync( byte[] buffer, int offset, int count, CancellationToken cancellationToken) // Task1 CancellationToken token = tokenSource.Token; await stream.ReadAsync(buf, 0, size, token); // Task2 // ReadAsyncの処理を中断させる tokenSource.Cancel();
61.
キャンセルトークンで死ぬ • これでいけそうに見える • が、実際はI/O処理を中断できない •
NetworkStreamがキャンセルトークンに 対応してない • え、タイムアウトどうやって実現する の?
62.
キャンセルトークンで死ぬ • Stack Overflow曰く •
「タイムアウトになったら別タスクで Closeすりゃ中断できるよ」 • これなら…いける!
63.
_人人人人人人_ > 突然の死 <  ̄Y^Y^Y^Y^Y ̄ キャンセルトークンで死ぬ
64.
キャンセルトークンで死ぬ static async Task
TestConnect() { try { var client = new TcpClient(); var task = Task.Run( () => client.ConnectAsync("localhost", 8080)); client.Close(); await task.ConfigureAwait(false); } catch (Exception) { } } これを10万回ぐらい呼び出すと大体死ぬ 全体コード
65.
キャンセルトークンで死ぬ • そもそもNetworkStreamは仕様的にはス レッドセーフではない • なので死ぬのは仕方がないという気も する •
そしてタイムアウト実現は振り出しに 戻る
66.
キャンセルトークンで死ぬ • 結局キューに詰めて一本化することで 何とかした
67.
キャンセルトークンで死ぬ • ReadAsyncやCloseをリクエストキュー に詰めて、 • ワーカータスクがそれを処理し、 •
結果をリプライキューに詰めたのを、 • 呼び出し元がリプライキューの結果を 読む
68.
キャンセルトークンで死ぬ public async Task<int>
ReadAsync( byte[] buf, int offset, int length, CancellationToken token) { // リクエストキューに詰めて await requestQueue.Enqueue(new Request() { Type = Operation.ReadAsync, Buf = buf, Offset = offset, Length = length, }).ConfigureAwait(false); // レスポンスキューに結果が返ってくるのを待つ var resp = await responseQueue.Dequeue(token) .ConfigureAwait(false); return resp.ReadResult; }
69.
キャンセルトークンで死ぬ public async Task<int>
ReadAsync( byte[] buf, int offset, int length, CancellationToken token) { // リクエストキューに詰めて await requestQueue.Enqueue(new Request() { Type = Operation.ReadAsync, Buf = buf, Offset = offset, Length = length, }).ConfigureAwait(false); // レスポンスキューに結果が返ってくるのを待つ var resp = await responseQueue.Dequeue(token) .ConfigureAwait(false); return resp.ReadResult; } responseQueueがCancellationTokenに対応してればいい
70.
キャンセルトークンで死ぬ async void Run()
{ while (true) { // リクエストを受け取り var op = await requestQueue.Dequeue().ConfigureAwait(false); // リクエスト毎の処理をして switch (op.Type) { case Operation.ReadAsync: var result = await client.ReadAsync( op.Buf, op.Offset, op.Length).ConfigureAwait(false); // レスポンスを返す await responseQueue.Enqueue(resp) .ConfigureAwait(false); break; case Operation.WriteAsync: ... } }
71.
キャンセルトークンで死ぬ • キューから1個ずつ取ってきて処理す るので、同時にReadAsyncやCloseが呼ば れたりしない • responseQueueがキャンセルトークンに 対応してるので、無事タイムアウト処 理ができるようになった
72.
キャンセルトークンで死ぬ • 結論: Monoは通信のタイムアウトすら簡 単に対応できない
73.
補足 • キャンセルトークンが使えないのは VC#でも同じ • ただし別タスクからCloseを呼び出しま くっても落ちなかった
74.
Q&A • これってちゃんとClose呼ばれるの? • 呼ばれないこともある •
でもソケットはSafeHandleなのでファ イナライザがうまいことやってくれる
75.
BufferBlockで死ぬ
76.
BufferBlockで死ぬ public async Task<int>
ReadAsync( byte[] buf, int offset, int length, CancellationToken token) { // リクエストキューに詰めて await requestQueue.Enqueue(new Request() { Type = Operation.ReadAsync, Buf = buf, Offset = offset, Length = length, }).ConfigureAwait(false); // レスポンスキューに結果が返ってくるのを待つ var resp = await responseQueue.Dequeue(token) .ConfigureAwait(false); return resp.ReadResult; } requestQueueとresponseQueueはどうやって作るの?
77.
BufferBlockで死ぬ • Queue<T>はスレッドセーフではない • ConcurrentQueue<T>はawaitで待てない •
async/awaitに対応したキューが必要
78.
BufferBlockで死ぬ • System.Threading.Tasks.Dataflow.BufferBlo ck が使えそう •
BufferBlock.SendAsync(data, token)で送信 • BufferBlock.ReceiveAsync(token)で受信 • キャンセルトークンが使える!
79.
_人人人人人人_ > 突然の死 <  ̄Y^Y^Y^Y^Y ̄ BufferBlockで死ぬ
80.
BufferBlockで死ぬ static async Task
SendTask(BufferBlock<string> bb) { for (int i = 0; i < 10000; i++) { await bb.SendAsync(i.ToString()).ConfigureAwait(false); await Task.Delay(1).ConfigureAwait(false); } } static async Task ReceiveTask(BufferBlock<string> bb) { for (int i = 0; i < 10000; i++) { try { await bb.ReceiveAsync(TimeSpan.FromMilliseconds(1)) .ConfigureAwait(false); } catch (Exception) { } } } SendTaskとReceiveTaskを同時に実行すると大体死ぬ 全体コード
81.
BufferBlockで死ぬ • 普通にバグ • ReceiveAsyncのタイムアウト時の処理で レースコンディション起こしてる
82.
BufferBlockで死ぬ • 結局自作した • AsyncMutex •
AsyncConditionVariable • AsyncQueue • 今のところ問題なく動いてる
83.
BufferBlockで死ぬ • 結論: Monoはまともに使えないライブ ラリを提供している
84.
SGenで死ぬ
85.
SGenで死ぬ • Mono曰く • SGen
is a new and powerful garbage collector.
86.
SGenで死ぬ _人人人人人人_ > 突然の死 <  ̄Y^Y^Y^Y^Y ̄
87.
SGenで死ぬ • しばらく動かしてると唐突に死ぬ • スタックトレースを見るとSGenの関数 内で死んでる •
new and powerful ェ…
88.
SGenで死ぬ • 古き良き Boehm
GC を使うと死ななく なった • ただしメモリが4GBまでしか使えない • 複数プロセス起動することで対応
89.
SGenで死ぬ • 結論: Monoはnew
and powerful (笑) な GCを提供している
90.
mmap(NONE)で死ぬ
91.
mmap(NONE)で死ぬ _人人人人人人_ > 突然の死 <  ̄Y^Y^Y^Y^Y ̄
92.
mmap(NONE)で死ぬ • しばらく動かしていると • mmap(...PROT_NONE...)
failed • というエラーを出して死ぬ
93.
mmap(NONE)で死ぬ • Issueにあるように、コンパイラのビル ド時に-DUSE_MMAPと-DUSE_MUNMAP を外す必要がある • Monoをソースからビルドし直し
94.
mmap(NONE)で死ぬ • Monoはしばらく動かしてると大体死ぬ
95.
メモリリークで死ぬ
96.
メモリリークで死ぬ
97.
メモリリークで死ぬ • 未解決問題 • 負荷が掛かっている場合だけメモリ使 用量が増え続ける •
ゲームサーバのコードが悪いせいなの かどうか分からない
98.
メモリリークで死ぬ • PHP製作者曰く: • 「僕なら、10リクエストごとにApache を再起動しますね。」 •
ということで、一定量動かしたらプロ セスを再起動するようにした
99.
メモリリークで死ぬ
100.
メモリリークで死ぬ • 結論: Monoはメモリリークを起こしてい るかも、と疑心暗鬼になるだけの下地 がある
101.
まとめ • Monoは人類には早かった • 次やるならクライアントをホストにす ると思う
102.
まとめ • とはいえ、async/awaitのおかげでサーバ のコードは相当短くなった • 全部で5,000行程度 •
※クライアントとの共通コードは除く •言い換えれば5,000行程度でMonoが死にま くったという…
103.
まとめ • Monoは(人間とプロセスが)死ぬ • 覚悟を持って使いましょう
104.
おわり
Descargar ahora