7. でも…
Copyright (C) 2014 Yahoo Japan Corporation. All Rights Reserved. 無断引用・転載禁止 7
8. 一般的にI/Oは遅い
L1
cache
reference
0.5
ns
L2
cache
reference
5
ns
Main
Memory
reference
100
ns
Send
1K
bytes
over
1Gbps
network
10,000
ns
0.01
ms
Read
4K
randomly
from
SSD
150,000
ns
0.15
ms
Round
trip
within
same
datacenter
500,000
ns
0.5
ms
Read
1
MB
sequentially
from
SSD
1,000,000
ns
1
ms
Disk
seek
10,000,000
ns
10
ms
Read
1
MB
sequentially
from
disk
20,000,000
ns
20
ms
Send
Packet
CA-‐Netherlands-‐CA
150,000,000
ns
150
ms
出典:Latency Numbers Every Programmer Should Know (抜粋)
https://gist.github.com/jboner/2841832
Copyright (C) 2014 Yahoo Japan Corporation. All Rights Reserved. 無断引用・転載禁止 8
9. ネットワーク
I/O遅い
サービス
分割で
I/O増加
ジレンマ
Copyright (C) 2014 Yahoo Japan Corporation. All Rights Reserved. 無断引用・転載禁止 9
33. node.js
• 1スレッド1プロセスだが、同時に複数の
リクエストをさばける
• あらゆるI/Oが徹底的に非同期化・多重化
されている
Copyright (C) 2014 Yahoo Japan Corporation. All Rights Reserved. 無断引用・転載禁止 33
34. node.jsの非同期API抽象化方針
• 多重化するところ(イベントループ)は
コアで処理
– 開発者は素直に処理を書くだけ
• Callbackスタイル
– クロージャ多用
Copyright (C) 2014 Yahoo Japan Corporation. All Rights Reserved. 無断引用・転載禁止 34
35. echoサーバー
var
net
=
require('net');
var
server
=
net.createServer(function(socket){
socket.write('Echo
serverrn');
socket.pipe(socket);
});
server.listen(1337,
'127.0.0.1');
Copyright (C) 2014 Yahoo Japan Corporation. All Rights Reserved. 無断引用・転載禁止 35
36. あとは、node.js自身が
うまいこと重ねてくれる
• たったこれだけのコードで
複数リクエストを同時にさばける
Copyright (C) 2014 Yahoo Japan Corporation. All Rights Reserved. 無断引用・転載禁止 36
61. hirak/co-httpclient
$
composer
require
'hirak/co-‐httpclient:dev-‐master'
Copyright (C) 2014 Yahoo Japan Corporation. All Rights Reserved. 無断引用・転載禁止 61
62. 通常の関数
function
getWebapi($url)
{
$req
=
new
HttpClientRequest($url);
$res
=
$req-‐send();
if
($res-‐getStatusCode()
=
400)
{
throw
new
RuntimeException($url);
}
return
json_decode($res-‐getBody());
}
Copyright (C) 2014 Yahoo Japan Corporation. All Rights Reserved. 無断引用・転載禁止 62
63. 非同期版の関数
function
getWebapiAsync($url)
{
$req
=
new
HttpClientRequest($url);
$res
=
(yield
$req);
if
($res-‐getStatusCode()
=
400)
{
throw
new
RuntimeException($url);
}
yield
json_decode($res-‐getBody());
}
Copyright (C) 2014 Yahoo Japan Corporation. All Rights Reserved. 無断引用・転載禁止 63
64. 起動
list($res1,
$res2)
=
co(
getWebapiAsync('http://example.com/a.json'),
getWebapiAsync('http://example.com/b.json')
);
Copyright (C) 2014 Yahoo Japan Corporation. All Rights Reserved. 無断引用・転載禁止 64
65. I/O多重化への修正
1. 待つところにyieldを挟んでおく。
2. returnをyieldに置き換える。
3. co関数で起動
これだけ!!
Copyright (C) 2014 Yahoo Japan Corporation. All Rights Reserved. 無断引用・転載禁止 65
66. 真の並行
Copyright (C) 2014 Yahoo Japan Corporation. All Rights Reserved. 無断引用・転載禁止 66
67. この一本を
ジェネレータ
関数にしてお
く
Copyright (C) 2014 Yahoo Japan Corporation. All Rights Reserved. 無断引用・転載禁止 67
68. co( )
co関数に渡すと、なるべく重ねな
がら実行してくれる
Copyright (C) 2014 Yahoo Japan Corporation. All Rights Reserved. 無断引用・転載禁止 68
69. yield方式のメリット
• 既存のPHPコードをあまり書き換えなく
て良い
– パラダイムを変えなくて良い
• interfaceを全て通過する
Copyright (C) 2014 Yahoo Japan Corporation. All Rights Reserved. 無断引用・転載禁止 69
71. 第4部 ‒ 補遺
どうやって実現しているのか
Copyright (C) 2014 Yahoo Japan Corporation. All Rights Reserved. 無断引用・転載禁止 71
72. yieldのおさらい
• 関数の処理を一時停止・再開できる機能
ジェネレータの例例ジェネレータを実⾏行行するコード例例
function
gen()
{
echo
(yield
1);
echo
(yield
2);
echo
(yield
3);
}
$g = gen();
echo $g-current();
echo $g-send(4);
echo $g-send(5);
$g-send(6);
Copyright (C) 2014 Yahoo Japan Corporation. All Rights Reserved. 無断引用・転載禁止 72
73. function
gen()
{
echo
(yield
1);
echo
(yield
2);
echo
(yield
3);
}
$g = gen();
echo $g-current();
echo $g-send(4);
echo $g-send(5);
$g-send(6);
← ここから起動 (ジェネレータの準備)
Copyright (C) 2014 Yahoo Japan Corporation. All Rights Reserved. 無断引用・転載禁止 73
74. function
gen()
{
echo
(yield
1);
echo
(yield
2);
echo
(yield
3);
}
$g = gen();
echo $g-current();
echo $g-send(4);
echo $g-send(5);
$g-send(6);
Copyright (C) 2014 Yahoo Japan Corporation. All Rights Reserved. 無断引用・転載禁止 74
75. function
gen()
{
echo
(yield
1);
echo
(yield
2);
echo
(yield
3);
}
$g = gen();
echo $g-current();
echo $g-send(4);
echo $g-send(5);
$g-send(6);
実行開始!
Copyright (C) 2014 Yahoo Japan Corporation. All Rights Reserved. 無断引用・転載禁止 75
76. function
gen()
{
echo
(yield
1);
echo
(yield
2);
echo
(yield
3);
}
$g = gen();
echo $g-current();
echo $g-send(4);
echo $g-send(5);
$g-send(6);
yieldが見つかったので…
Copyright (C) 2014 Yahoo Japan Corporation. All Rights Reserved. 無断引用・転載禁止 76
77. function
gen()
{
echo
(yield
1);
echo
(yield
2);
echo
(yield
3);
}
$g = gen();
echo 1;
echo $g-send(4);
echo $g-send(5);
$g-send(6);
(一時停止中)
1
Copyright (C) 2014 Yahoo Japan Corporation. All Rights Reserved. 無断引用・転載禁止 77
78. function
gen()
{
echo
(yield
1);
echo
(yield
2);
echo
(yield
3);
}
$g = gen();
echo 1;
echo $g-send(4);
echo $g-send(5);
$g-send(6);
(一時停止中)
1
Copyright (C) 2014 Yahoo Japan Corporation. All Rights Reserved. 無断引用・転載禁止 78
79. function
gen()
{
echo
(4);
echo
(yield
2);
echo
(yield
3);
}
$g = gen();
echo 1;
echo $g-send(4);
echo $g-send(5);
$g-send(6);
14
Copyright (C) 2014 Yahoo Japan Corporation. All Rights Reserved. 無断引用・転載禁止 79
80. function
gen()
{
echo
(4);
echo
(yield
2);
echo
(yield
3);
}
$g = gen();
echo 1;
echo $g-send(4);
echo $g-send(5);
$g-send(6);
14
Copyright (C) 2014 Yahoo Japan Corporation. All Rights Reserved. 無断引用・転載禁止 80
81. function
gen()
{
echo
(4);
echo
(yield
2);
echo
(yield
3);
}
$g = gen();
echo 1;
echo 2;
echo $g-send(5);
$g-send(6);
142
(一時停止中)
Copyright (C) 2014 Yahoo Japan Corporation. All Rights Reserved. 無断引用・転載禁止 81
82. function
gen()
{
echo
(4);
echo
(yield
2);
echo
(yield
3);
}
$g = gen();
echo 1;
echo 2;
echo $g-send(5);
$g-send(6);
142
(一時停止中)
Copyright (C) 2014 Yahoo Japan Corporation. All Rights Reserved. 無断引用・転載禁止 82
83. function
gen()
{
echo
(4);
echo
(5);
echo
(yield
3);
}
$g = gen();
echo 1;
echo 2;
echo $g-send(5);
$g-send(6);
1425
Copyright (C) 2014 Yahoo Japan Corporation. All Rights Reserved. 無断引用・転載禁止 83
84. function
gen()
{
echo
(4);
echo
(5);
echo
(yield
3);
}
$g = gen();
echo 1;
echo 2;
echo $g-send(5);
$g-send(6);
1425
Copyright (C) 2014 Yahoo Japan Corporation. All Rights Reserved. 無断引用・転載禁止 84
85. function
gen()
{
echo
(4);
echo
(5);
echo
(yield
3);
}
$g = gen();
echo 1;
echo 2;
echo 3;
$g-send(6);
14253
(一時停止中)
Copyright (C) 2014 Yahoo Japan Corporation. All Rights Reserved. 無断引用・転載禁止 85
86. function
gen()
{
echo
(4);
echo
(5);
echo
(yield
3);
}
$g = gen();
echo 1;
echo 2;
echo 3;
$g-send(6);
14253
(一時停止中)
Copyright (C) 2014 Yahoo Japan Corporation. All Rights Reserved. 無断引用・転載禁止 86
87. function
gen()
{
echo
(4);
echo
(5);
echo
(6);
}
$g = gen();
echo 1;
echo 2;
echo 3;
$g-send(6);
142536
Copyright (C) 2014 Yahoo Japan Corporation. All Rights Reserved. 無断引用・転載禁止 87
88. function
gen()
{
echo
(4);
echo
(5);
echo
(6);
}
$g = gen();
echo 1;
echo 2;
echo 3;
null;
142536
Copyright (C) 2014 Yahoo Japan Corporation. All Rights Reserved. 無断引用・転載禁止 88
89. co-httpclientの場合
co関数
gen
gen
gen
Copyright (C) 2014 Yahoo Japan Corporation. All Rights Reserved. 無断引用・転載禁止 89
90. 1. 与えられたジェネレータを
順番に実行していく
co関数
gen
gen
gen
実行
Copyright (C) 2014 Yahoo Japan Corporation. All Rights Reserved. 無断引用・転載禁止 90
91. 1. 与えられたジェネレータを
順番に実行していく
co関数
gen
gen
gen
実行
Copyright (C) 2014 Yahoo Japan Corporation. All Rights Reserved. 無断引用・転載禁止 91
92. 2. yieldされたら…
co関数
gen
yieldRequest
gen
gen
Copyright (C) 2014 Yahoo Japan Corporation. All Rights Reserved. 無断引用・転載禁止 92
93. 3. 非同期実行し始めて…
co関数
gen
yield
gen
gen
⾮非同期実⾏行行中
Request
Copyright (C) 2014 Yahoo Japan Corporation. All Rights Reserved. 無断引用・転載禁止 93
94. 4. 待っている間に次の
ジェネレータを実行
co関数
gen
yield
gen
gen
⾮非同期実⾏行行中
Request
Copyright (C) 2014 Yahoo Japan Corporation. All Rights Reserved. 無断引用・転載禁止 94
95. 5. やることがなくなったら
非同期実行を待って…
co関数
gen
yield
gen
gen
⾮非同期実⾏行行中(終わ
るまで待つ)
Request
Copyright (C) 2014 Yahoo Japan Corporation. All Rights Reserved. 無断引用・転載禁止 95
96. 6. ジェネレータを再開!
co関数
gen
yieldRequest
gen
gen
Copyright (C) 2014 Yahoo Japan Corporation. All Rights Reserved. 無断引用・転載禁止 96
97. つまり
• yield = コンテキストスイッチ
• co関数はyieldされる度に次に行う処理を
探して実行する
• スレッドっぽい
– 軽量スレッドと呼ばれる所以
Copyright (C) 2014 Yahoo Japan Corporation. All Rights Reserved. 無断引用・転載禁止 97
98. その他の工夫
• 非同期関数内で別の非同期関数を呼ぶ
– SplStackを使って対処
• 例外の伝搬
– Generator::throw()を使用する
非常に参考にしました↓
Cooperative multitasking using coroutines (in PHP!)
http://nikic.github.io/2012/12/22/Cooperative-multitasking-using-coroutines-in-PHP.html
Copyright (C) 2014 Yahoo Japan Corporation. All Rights Reserved. 無断引用・転載禁止 98
99. 関数内で別の関数を呼ぶ
//通常の関数
function a() {
return b() . c();
}
//非同期の関数
function aAsync() {
yield (yield bAsync()) . (yield cAsync());
Copyright (C) 2014 Yahoo Japan Corporation. All Rights Reserved. 無断引用・転載禁止 99
}
100. こんな書き方もできる
//非同期関数の配列
function aAsync() {
$arr = (yield [bAsync(), cAsync()]);
yield implode('', $arr);
Copyright (C) 2014 Yahoo Japan Corporation. All Rights Reserved. 無断引用・転載禁止 100
}
101. 第5部
まとめと今後の展望
10
Copyright (C) 2014 Yahoo Japan Corporation. All Rights Reserved. 無断引用・転載禁止 1
102. まとめ
• I/O多重化してマイクロサービスに備えよう
• PHPにcallbackスタイルはつらい…
• yieldでも抽象化できる
– こっちの方が既存のPHPコードと互換性が高い
• curl_multiに関して実装を書いてみた
Copyright (C) 2014 Yahoo Japan Corporation. All Rights Reserved. 無断引用・転載禁止 102
103. 今後の展望
• curl_multi以外にmysqlndや
postgresqlも重ねたい
• 例外のスタックトレースサポート
• コードのブラッシュアップ
Pull Request歓迎!
Copyright (C) 2014 Yahoo Japan Corporation. All Rights Reserved. 無断引用・転載禁止 103
104. hirak/co-httpclient
$
composer
require
'hirak/co-‐httpclient:dev-‐master'
104
再掲
Copyright (C) 2014 Yahoo Japan Corporation. All Rights Reserved. 無断引用・転載禁止