Upgrade to Pro
— share decks privately, control downloads, hide ads and more …
Speaker Deck
Sign up for free
Menu
Search
Features
All features
Private URLs
Password Protection
Custom URLS
Scheduled publishing
Remove Branding
Restrict embedding
Deck Collections
Notes
Features
All features
Private URLs
Password Protection
Custom URLS
Scheduled publishing
Remove Branding
Restrict embedding
Deck Collections
Notes
Explore
Featured decks
Featured speakers
Programming
Technology
Storyboards
Explore
Featured decks
Featured speakers
Programming
Technology
Storyboards
Pricing
Search
Sign in
Sign up for free
array_typed
Search
Sponsored
·
Ship Features Fearlessly
Turn features on and off without deploys. Used by thousands of Ruby developers.
→
yoya
November 23, 2015
Programming
2.2k
0
Share
Embed
Copy iframe code
Copy JS code
Copy link
Start on current slide
array_typed
自作Arrayでメモリ節約
yoya
November 23, 2015
More Decks by yoya
See All by yoya
resize_nitpick
yoya
1
190
ImageFluxBinary
yoya
2
3k
HEIF-kaisetsu
yoya
4
3.6k
go-thumber-imagick
yoya
1
210
chokaizomae
yoya
2
620
wildimagebinary
yoya
1
230
goimagicksyokai
yoya
2
1.2k
GoImagickThumbnail
yoya
0
1.7k
sushigazou
yoya
0
12k
Other Decks in Programming
See All in Programming
市販E-Readerを乗っ取れ 〜Embedded Swiftで電子ペーパーガジェットを制御する〜
trickart
0
130
XHTMLが残したもの
yosuke_furukawa
PRO
2
470
ソフトウェアラスタライザ
fadis
1
800
FastAPI の並行処理モデルを完全に理解する
hoto17296
9
3.9k
業務時間外もAIに働いてもらう話
colorful12
3
10k
AI Agent時代のリアーキテクチャ戦略と実践
hokaccha
6
3k
RSSとCodexを使ってX投稿自動化してみた
ochtum
0
110
【高い買い物LT会】初任給で話題の国産フィジカルAIを買った話
akagami
PRO
0
130
Go × SIMDで高速化するベクトル検索 ~ルーフラインモデルでSIMDが効く境界を探れ! ~
po3rin
1
180
Foundry Localでエージェント開発
seosoft
0
160
世界の中心で、AI(App Intents)をさけぶ ー App Intents中心設計の実践ガイド
touyou
0
220
LLMは4年分のCompose移行を再現できるのか?実プロダクト279件のXMLで探る自動化の境界線
makun
0
450
Featured
See All Featured
Stewardship and Sustainability of Urban and Community Forests
pwiseman
0
520
How to Get Subject Matter Experts Bought In and Actively Contributing to SEO & PR Initiatives.
livdayseo
0
190
Leading Effective Engineering Teams in the AI Era
addyosmani
9
2.6k
Are puppies a ranking factor?
jonoalderson
2
3.9k
Music & Morning Musume
bryan
47
7.4k
YesSQL, Process and Tooling at Scale
rocio
174
15k
Balancing Empowerment & Direction
lara
6
1.3k
The Limits of Empathy - UXLibs8
cassininazir
1
650
Navigating Weather and Climate Data
rabernat
0
510
Building Flexible Design Systems
yeseniaperezcruz
330
41k
Ecommerce SEO: The Keys for Success Now & Beyond - #SERPConf2024
aleyda
1
2.1k
Technical Leadership for Architectural Decision Making
baasie
3
560
Transcript
自作ArrayでPHPのメモリ節約 2015年11月23日(火) “よや”
[email protected]
自己紹介 • h8ps://osdn.jp/users/yoya/ • h8ps://github.com/yoya/ • 元Flashバイナリ屋
– h8ps://osdn.jp/projects/swfed/ – モバイルFlashが終わって仕事がなくなりました • ImageMagick マニア – 差分追ってます – h8p://d.hatena.ne.jp/yoya/searchdiary? word=ImageMagick twi8er_id:yoya
【問題提起】 PHPの配列は重たい $size = 20 * 1024*1024; // 20M
$arr = array(); for ($i = 0 ; $i < $size; $i++) { $arr[$i] = $i; } $total = 0; for ($i = 0 ; $i < $size; $i++) { $total += $arr[$i]; } • CPU: user 0m12.174s sys 0m2.568s • Memory: 2.9GB • CPU: user 0m0.384s sys 0m0.132s Memory: 157MB PHPの 現実 size := 20 * 1000 * 1000; arr := make([]int, size) for i := 0; i < size; i++ { arr[i] = i } total := 0 for i := 0; i < size; i++ { total += arr[i] } ちなみに Golang だと
何故 PHP array は重たいのか h8ps://drive.google.com/file/d/0B3UKOMH_4lgBUTdjUGxIZ3l1Ukk/view
もう少し分かりやすい図 ・つまりDataコンテナもArray管理データも大きい h8ps://catchy.io/slides/PHP-‐Data-‐Structures-‐and-‐the-‐impact-‐of-‐PHP-‐7-‐on-‐them.html
SplFixedArray の方は? ・Array管理データがごそっと減ってる h8ps://catchy.io/slides/PHP-‐Data-‐Structures-‐and-‐the-‐impact-‐of-‐PHP-‐7-‐on-‐them.html テーブル長固定 双方向リスト 構造無し
SplFixedArray で1/3に $size = 20 * 1024*1024; // 20M
$arr = array(); for ($i = 0 ; $i < $size; $i++) { $arr[$i] = $i; } $total = 0; for ($i = 0 ; $i < $size; $i++) { $total += $arr[$i]; } • CPU: user 0m12.174s sys 0m2.568s • Memory: 2.9GB 普通の Array $size = 20 * 1024*1024; // 20M $arr = new SplFixedArray($size); for ($i = 0 ; $i < $size; $i++) { <あとは同じ> • CPU: user 0m3.779s sys 0m0.637s • Memory: 1.0GB SplFixedArray
【提案】もっと節約したい • 使える値をUint8 (0〜255)に絞る (制約) – メモリに等間隔で詰めて並べられるので有利 – Stringに保存する事で管理も殆どしない
Uint8Array String (5文字) 0 1 2 3 $a = Uint8Array(5) $a[1] = 7; var_dump($a[3]); 4
array自体をPHPで実装出来る • 配列風 class を実現する以下の機能がある – ArrayAccess • $a[〜]
= 7 のようにアクセスできる – Countable • count($a) で配列数がわかる – Iterator • foreach($a as $e) でループ出来る class MyArray implements ArrayAccess, Countable, Iterator {
AccessArray • get,set,isset,unset を実装 class Uint8Array implements ArrayAccess {
protected $container; funcmon __construct($n) { $this-‐>arraySize = $n; $this-‐>container = str_repeat("\0", $n); } public funcmon offsetGet($offset) { return ord($this-‐>container[$offset]); } public funcmon offsetSet($offset, $value) { $this-‐>container[$offset] = chr($value); } public funcmon offsetExists($offset) { ;;; } public funcmon offsetUnset($offset) { ;;; } } $a = new Uint8Array(5); $a[2] = 7; var_dump($a[1], $a[2]); => int(0) int(7)
Countable • count を実装 class Uint8Array implements ArrayAccess,
Countable { protected $container; funcmon __construct($n) { $this-‐>arraySize = $n; $this-‐>container = str_repeat("\0", $n); } <略> public funcmon count() { return $this-‐>arraySize; } } $a = new Uint8Array(5); var_dump(count($a)); => int(5)
Iterator • current,next,key,valid,rewind を実装 class Uint8Array implements ArrayAccess,
Countable, Iterator { <略> public funcmon current() { return $this-‐>offsetGet($this-‐>iterPos); } public funcmon next() { $this-‐>iterPos++; } public funcmon key() { return $this-‐>iterPos; } public funcmon valid() { return $this-‐>iterPos < $this-‐>arraySize; } public funcmon rewind() { $this-‐>iterPos = 0; } } $a = new Uint8Array(5); $a[2] = 7; foreach ($a as $e) { var_dump($e); } => int(0) int(0) int(7) int(0) int(0) Iterator の cursor
Uint8Array でメモリ大幅節約 $size = 20 * 1024*1024; // 20M
$arr = array(); for ($i = 0 ; $i < $size; $i++) { $arr[$i] = $i % 256; } $total = 0; for ($i = 0 ; $i < $size; $i++) { $total += $arr[$i]; } • CPU: user 0m12.174s sys 0m2.568s • Memory: 2.9GB 普通の Array $size = 20 * 1024*1024; // 20M $arr = new Uint8Array($size); for ($i = 0 ; $i < $size; $i++) { <あとは同じ> • CPU: user 0m27.828s sys 0m0.121s • Memory: 20MB Uint8Array メモリ使用量 100分の1
注意点3つ 自作Arrayの注意点 (SplFixedArray とほぼ共通) • (1) array_〜 系関数が使えない
• array_slice や array_join が(そのままだと)使えない • (2) is_array に引っかからない • is_object なので • (3)要素を再帰的に持つ場合に注意 • SplFixedArray だと要素を参照渡しできない • 今回の自作Arrayだとそもそも再帰的に持てない
(1) array_〜系関数が使えない • toArray で標準arrayに変換してから渡す – SplFixedArray は toArray メソッドがある
• array_slice は真面目に作る必要がありそう • 一部切り出すのにtoArrayで展開するとメモリが辛い funcmon toArray() { $arr = array(); $arraySize = $this-‐>arraySize; for ($i = 0 ; $i < $arraySize ; $i++) { $arr []= $this-‐>offsetGet($i); } return $arr; } 作ればいい
(2) is_array にひっかからない • ArrayAccess 実装は is_array 対象ではない require_once("Uint8Array.php");
$a1 = array(); $a3 = new SplFixedArray(3); $a3 = new Uint8Array(3); echo “# is_array¥n”; var_dump(is_array($a1)); var_dump(is_array($a2)); var_dump(is_array($a3)); echo “# instanceof¥n”; var_dump($a2 instanceof SplFixedArray); var_dump($a3 instanceof Uint8Array); var_dump($a2 instanceof ArrayAccess); var_dump($a3 instanceof ArrayAccess); # array bool(true) bool(false) bool(false) # Instanceof bool(true) bool(true) bool(true) bool(true)
(3)要素を参照渡しできない ※SplFixedArray の話、蛇足 • 構造を再帰的に持つときに致命的 $arr = [1, 2,
[31,32,33], 4]; print_r($arr); add($arr); print_r($arr); funcmon add(&$arr) { if (is_array($arr)) { foreach ($arr as &$e) { add($e); } } else { $arr += 1; } } 1 2 * 4 31 32 33 PHP Nomce: Indirect modificamon of overloaded element of SplFixedArray has no effect in /home/yoya/ array_ref.php on line 8 全部1足す 2 3 * 5 32 33 34 SplFixedArray だと エラー
Array_Typed • h8ps://github.com/yoya/Array_Typed – 使い方サンプル <?php require 'vendor/autoload.php';
$arr = new Array_Uint8(1024); $arr[100] = 0x7F; var_dump($arr[100]); $arr = new Array_Sint8(1024); $arr[100] = -‐0x80; var_dump($arr[100]); Array_{Uint8,Sint8,Uint16,Sint16} の4つをご用意しました int(127) int(-‐128)
ご利用上の注意 • 利用出来る値の範囲は限られます – Uint8: 0〜255、Sint8: -‐128〜127 –
Uint16: 0〜65535、Sint16: -‐32768〜32767 • 圧倒的な省メモリ、だけど CPU は数倍重たい • 以下は SplFixedArrayと共通のTips – 配列の長さは固定です。あとで増減出来ません – Array_〜関数を使うときは toArray() で変換して渡す – 再帰構造の途中には使わない。リーフ限定にする – is_array の代わりに instanceof でチェック
備考 • PHP7 だと Array が大分軽い – 冒頭の 20*1024*1024
配列を読み書きするコード • PHP拡張にすればCPUとメモリの両方に優しい仕 組みが作れるはず > 若いものに任せます、作り方なら教えるYO! PHP5 PHP7 array 12.2sec, 2.9GB 1.7sec, 1.0GB SplFixedArray 3.8sec, 1.0GB 1.6sec, 320MB Uint8Array 27.8sec, 20MB 15.2sec, 20MB
以上です twi8er_id:yoya で質問承ります