Rust Advent Calendar 2019 1æ¥ç® Rust ã®éåæããã°ã©ãã³ã°ã¢ãã«ã¯ã©ã³ã¿ã¤ã 観ç¹ã 㨠Go ã®ããã«ä¼¼ã¦ãã
ãã®è¨äºã¯ Rust Advent Calendar 2019 ã®1æ¥ç®ã®è¨äºã«ãªãã¾ã.
ææ¥ã¯ topecongiro ããã®äºå®ã§ã.
TL;DR
å»ã 11/07 ã« Rust 1.39.0 ããªãªã¼ã¹ããã¾ãã. ããã¯ã¦ã¼ã¶ã¼å¾ æã® async/await æ§æãè¨èªæ©è½ã¨ãã¦åãè¾¼ã¾ããå®å®çãªãªã¼ã¹ã¨ãªãã¾ã. Advent Calendar æåã®è¨äºã¨ãã¦ã¯åãä¸ããªãããã«ã¯ããã¾ãã.
ããæ¢ã«ä»ã®è¯ãè¨äºãããããæ¸ããã¦ãã¾ãã, ãã®è¨äºã§ã¯ããããè£å®ããè¦ç¹ãã説æãã¦ã¿ããã¨æãã¾ã.
- Rust ã¨éåæ IO ã®æ´å²
- κeenã®Happy Hacκing Blog -- async/awaitã¨åæå¯è½æ§
- async/await ã®å®è£ ã¨å©ä¾¿æ§ã®ãã©ã³ã¹ã®è¯ãã«ã¤ãã¦.
- κeenã®Happy Hacκing Blog -- Rustã®Futureã¨ãã®Runnerãä½ã£ã¦ã¿ã
- runtime ãèªä½ãããã¨ã«ãã£ã¦ç解ã§ãã.
- äºå±±æ¢åæ´å²é¤¨ -- Rustã¸ã§ãã¬ã¼ã¿å¾¹åºè§£èª¬
- async/await ã®è±ç³ãã³ã³ãã¤ã©ã®å é¨å®è£ , Pin ãªã©ã«ã¤ãã¦. 詳ããç¥ããã人åã.
- std::pin ã®åæ
- Pin ã«ã¤ãã¦ã®ãããããã解説.
async/await æ§æèªä½ã®è§£èª¬ãè¨èªæ©è½ã¨ãã¦ã©ãå®è£ ãããã¨ãã話ã¯å¤ãã®ã§,
- ä½æ async/await ã«ããéåæã¢ãã«ãã¦ã¼ã¶ã¼, è¨èªå®è£ ã®ä¸¡è¦³ç¹ããæ±ãæãã®ã.
- runtime 㧠Future ãå¹ççã«å®è¡ããããã®å·¥å¤«.
ãããã®å ¥éçãªè©±ããããã¨æãã¾ã.
async/await ã®æ¦å¿µèªä½ã¯ç¥ã£ã¦ãã人ã対象ã§ã.
async/await ç¥ããªããã£ã¦äººã¯, ã¾ã㯠OPTiM TECH BLOG -- Rustã®éåæããã°ã©ãã³ã°ããã¹ã¿ã¼ãã ãèªãã®ãè¯ãã§ããã.
ãããããªéåæããã°ã©ãã³ã°ã¢ãã«
ãé¡ã¨ãã¦, web ãµã¼ãã¼ã§å¤§éã®ãªã¯ã¨ã¹ããæããã¨ãèãã¾ã.
- ãµã¼ãã¼1å°ããããåä½æéã«æãããªã¯ã¨ã¹ãã®æ°(ã¹ã«ã¼ããã).
- ãªã¯ã¨ã¹ãæ¯ã®å¾ ã¡æé(ã¬ã¤ãã³ã·).
ããããææ¨ã«ãªãã¾ã.
ã·ã³ã°ã«ã¹ã¬ãã (éåææ©æ§ãªã)
ãã®ãããåç´ãªå ´åã¨ãã¦, 16ã³ã¢ã® CPU ãç©ãã ãµã¼ãã¼ã« web ã¢ããªã®ããã»ã¹ãã²ã¨ã¤ãã£ã¦, ãããã·ã³ã°ã«ã¹ã¬ããã§åãã¦ãããããªå ´åãèãã¦ã¿ã¾ã.
use std::net::TcpListener; fn main() { let listener = TcpListener::bind("127.0.0.1:80").unwrap(); for stream in listener.incoming() { let stream = stream.unwrap(); // ä½ãã®å¦çããã. } }
å¼ç¨: https://doc.rust-lang.org/book/ch20-01-single-threaded.html
ä¸åº¦ã«100ãªã¯ã¨ã¹ãã®ã¢ã¯ã»ã¹ãæ¥ãã¨ã, ãã®ããã»ã¹ã¯ãããé çªã«å¦çãã¦ããã¾ã.
ãªã®ã§, ä¾ãã°1ãªã¯ã¨ã¹ãã®å¦çã«0.1ç§ããããããªå ´å, 100åç®ã®ãªã¯ã¨ã¹ãã¯ç´10ç§å¾ ãããããã¨ã«ãªãã¾ã.
ãããã³ãããªãã¨ã許容ããããã¨ããªãã§ããã. ãªã®ã§, éåæã«å¦çãããå¿ è¦ãããã¾ã.
ãªã¯ã¨ã¹ãæ¯ã«ã¹ã¬ãããç«ã¦ã
ãªã¯ã¨ã¹ãæ¯ã«ã¹ã¬ãããç«ã¦ãã°ã©ãã§ãããã.
fn main() { let listener = TcpListener::bind("127.0.0.1:80").unwrap(); for stream in listener.incoming() { let stream = stream.unwrap(); thread::spawn(|| { handle_connection(stream); }); } }
å¼ç¨: https://doc.rust-lang.org/book/ch20-02-multithreaded.html
16åããã³ã¢ã使ãåãã¦, ä¸çªé ãã¬ã¹ãã³ã¹(ææªã®ã¬ã¤ãã³ã·)㯠100 * 0.1 / 16 = 0.625 ç§å¾ã«ãªãã¾ã.
ããã§ããããã«ãè¦ãã¾ãã, 1ãªã¯ã¨ã¹ãããã 0.001 ç§ããã API ã« 10000 ãªã¯ã¨ã¹ãæ¥ãå ´åã¯ã©ããªãã§ãããã.
ãã®å ´åã¯åæã« 10000 ã¹ã¬ããç«ã¤ãã¨ã«ãªãã¾ãã,
- ãã®ã¹ã¬ãããã¡ã管çããã®ã¯ OS ã§ã. (ãããã) OS 㯠CPU ã使ãããã¹ã¬ãããã¡ãå ¬å¹³ã« CPU ã使ããããã«, ä¸å®æéãã¨ã« CPU ã使ããã¹ã¬ãããåãæ¿ãã¾ã. ã¹ã±ã¸ã¥ã¼ãªã³ã°ã®ã³ã¹ãã¨ã³ã³ãã¯ã¹ãã¹ã¤ããã®ã³ã¹ãããããã¾ãã, ãããã¯ãããªãã«é«ä¾¡ã§ã.
- 1 OS ã¹ã¬ããæ¯ã«ãã®ã¹ã¬ããã使ãã¹ã¿ãã¯é å(ã¡ã¢ãª)ã確ä¿ããå¿ è¦ãããã¾ã. ãã®ã¹ã¿ãã¯ã®ãµã¤ãºã¯å¾ããå¤æ´ã§ããªãã®ã§, ååãªãµã¤ãºãå²ãå½ã¦ã¦ããå¿ è¦ãããã¾ã. (ã¹ã¿ãã¯ã«ã¤ãã¦ã¯ Performance without the event loop ã«ãããããã説æãããã¾ã.)
ãã®ãã, ã¹ã¬ããæ°ãã³ã¢æ°ãããå¤§å¹ ã«å¤§ããå ´åã¯æ§è½ãå£åãã¾ã. ãã®åé¡ã解決ããããã«ã¯, 使ç¨ãã OS ã¹ã¬ããæ°ãæããå¿ è¦ãããã¾ã.
ã¹ã¬ãããã¼ã«
ãããã£ãç¨éã§ç¨ããããã®ãã¹ã¬ãããã¼ã«ã§ã.
fn main() { let listener = TcpListener::bind("127.0.0.1:80").unwrap(); let pool = ThreadPool::new(16); for stream in listener.incoming() { let stream = stream.unwrap(); pool.execute(|| { handle_connection(stream); }); } }
å¼ç¨: https://doc.rust-lang.org/book/ch20-02-multithreaded.html
ããã¯æåã«èª¬æããã·ã³ã°ã«ã¹ã¬ããã®ãã®ãã¹ã¬ãããã¼ã«ã®ãµã¤ãºå(ããã§ã¯16å)並ã¹ããã®ã¨æããã¨ãã§ãã¾ã. (Perl, Ruby, Python ãªã©ã§ãããã prefork åã®ä¸¦ååãéåæããã°ã©ãã³ã°ã¢ãã«ã¨ãã¦ã¯ããã¨ä¼¼ããããªãã®ã§ã.)
1ãªã¯ã¨ã¹ãããã 0.001 ç§ããã API ã« 10000 ãªã¯ã¨ã¹ãæ¥ãå ´å, æ§è½å£åããªã, ææªã®ã¬ã¤ãã³ã·ã¯ 0.625 ç§ã§ã.
ããã§ã¨ã! ããã§ã³ã¢ããã«ã«ä½¿ããããã«ãªãã¾ãã!
ã¨è¨ãããã¨ããã§ãã, ããã§ãã¾ã ä¸ååã§ã.
fn main() { let listener = TcpListener::bind("127.0.0.1:80").unwrap(); let pool = ThreadPool::new(16); for stream in listener.incoming() { let stream = stream.unwrap(); pool.execute(|| { handle_connection(stream); }); } } fn handle_connection(mut stream: TcpStream) { let x = call_other_api(); // å¤é¨ API å¼ã³åºã. 0.999 ç§ããã. process_something(x); // ãã®ããã»ã¹ã§ã®å¦ç. 0.001 ç§ããããããªã. }
ä¾ãã°, å¦çã«1ç§ããã API ã®ä¸ã§å¤é¨ãµã¼ãã¹ã® API å¼ã³åºãããã¦ãã¦, ãã®å¼ã³åºãã« 0.999 ç§ããã£ã¦ããã¨ãã¾ã.
ãã®ãµã¼ãã¼èªä½ã¯æ®ã©å¦çããã¦ããªãã®ã«, åæã«å¦çã§ãããªã¯ã¨ã¹ãã®æ°ã¯æ大ã§ãã¹ã¬ãããã¼ã«ã®ãµã¤ãºåã§ã.
ã¤ã¾ã RPS (Request Per Second; 1ç§ãããã«å¦çã§ãããªã¯ã¨ã¹ãæ°)ã¯
RPS = ã¹ã¬ãããã¼ã«ã®ãµã¤ãº / å¦çã«ãããæé
ã«ãªãã¾ã. ä¸ã®ä¾ã ã¨ç§é 16 ãªã¯ã¨ã¹ãããæãã¾ãã.
å¥ã®æ¯è²ã®éãä¾ã¨ãã¦ã¯, ã¨ãã£ã¿ãªã©ã® GUI ã¢ããªã±ã¼ã·ã§ã³ã§åã³ã³ãã¼ãã³ãã並åã«åãããããªå ´åã§ã.
ã¹ã¬ãããã¼ã«ã®ãµã¤ãºããå¤ãã®ã³ã³ãã¼ãã³ããã¡ãåæã«(人éãå¤é¨ããã»ã¹ã¨ã®éä¿¡ãªã©ã§)å ¥åå¾ ã¡ããããã¨ããã¨, ã¹ã¬ããã足ããã«ãããããã¯ãã¾ã.
ã¾ã, ãã®ã±ã¼ã¹ã ã¨å¦çã®è² è·ã¯ãã¾ãåé¡ã«ãªããªããã¨ãå¤ãã®ã§, ãµã¤ãºãåºå®ããªãã¹ã¬ãããã¼ã«ã使ãã¨ããé¸æè¢ãããã¾ãã.
ãããã®ã±ã¼ã¹ã§å ±éããã®ã¯, ãå¦çã®ã³ã³ããã¹ããä¿æããã¾ã¾, blocking ãªå¦çãããããã¨ãããã¨ã§ã.
(blocking ãªå¦çã¨ããã®ã¯, æ£ç¢ºã§ã¯ãªãã§ããã©ãã«è¨ãã°ãCPU ãæ¶è²»ããªããæéããããå¦çãã®ãã¨ã§ã.)
ããã«ã¯ã³ã«ã¼ãã³ãå©ç¨ã§ãã¾ã.
ã³ã«ã¼ãã³
é常ã®é¢æ°ã¯å¼ã³åºããå¾ã¯ return ãããã ãã§ã. ããã«å¯¾ã, å¼ã³åºããå¾ã«ä¸æã§ä¸åº¦å¦çãæ»ã, å¾ã§åéã§ãããã®ã®ãã¨ãã³ã«ã¼ãã³ã¨è¨ãã¾ã.
ã³ã«ã¼ãã³ã«ã¯ symmetric/asymmetric ãªãã®ã¨ stackful/stackless ã®ãã®ããã, è¨èªãã©ã¤ãã©ãªã«ãã£ã¦éãã¾ã.
ãå¦çã®ã³ã³ããã¹ããä¿æããã¾ã¾, blocking ãªå¦çãããããã¨ããæèã§ä¸çªç°¡åãªã®ã¯ asymmetric stackful coroutine ã§ã.
å®è£ æ¹æ³ã¨ãã¦ä¾ãã°, é¢æ°å¼ã³åºãæã«ã¹ã¬ãããç«ã¦ã¦æ»ãå¤è¿å´/å¦çåéç¨ã® channel ãä¸ãã¦å¼ã³åºã, å¦çãæ»ãããå ´åã¯æ»ãå¤è¿å´ç¨ã® channel ã«å¤ãæµãã¦å¦çåéç¨ã® channel ã§å¾ ã¤ããã«ãã¾ã.
(Go ã®ããã°ã©ã ãæ¸ãã¨ãã«ä¼¼ããããªãã¿ã¼ã³ãé »åºããã¨æãã¾ã.)
ãã®ãã¹ã¬ãããèªåã® stack ãæã£ã¦ãããã¨ããã®ã stackful, ãå¼ã³åºãå ã«ããå¦çãå§è²ã§ããªããã¨ããã®ã asymmetric ã§ã.
éã« symmetric coroutine ã¯å¼ã³åºãå 以å¤ã«ãå¦çãå§è²ã§ãã¾ã. å¦çã®å§è²ãããã®ãã次ã®å¦çãè¡ããã¨ããã²ã¨ã¤ã§, é¢æ°ãå¼ã³åºãã®ãå¤ãæ»ãã®ãåãåä½ã§ã§ãããã symmetric ãªããã§ã.
symmetric stackful coroutine ã«è¿ãã¢ãã«ã Rust/tokio ã® blocking API ã§ã.
https://qiita.com/legokichi/items/30e577d996851b6b3ba1
blocking å¦çã®ããã«ããç¨ã®ã¹ã¬ãããã¼ã«ã«èªåã§å ¥ã, å¥ã®ã¹ã¬ããã«å¦çãå§è²ãã¾ã.
ãã , ããã¯ã¹ã¬ãããã¼ã«ã®ãµã¤ãºåé¡ãç·©åããããã®ãã®(ã¨ãã風ã«ç解ãã¦ãã)ã§ãã, ã³ã³ããã¹ãã¹ã¤ãããçºçããåé¡ã¯æ®ã£ã¦ãã¾ã.
ã³ã«ã¼ãã³ã«ã¤ãã¦ã¯ä»ã«ãè²ã ããã®ã§ããã§ã¯è©³ããã¯è¿°ã¹ã¾ãã. (ã¨ãããèªåãããã¾ã§è©³ãããªã.) 詳ããç¥ãããæ¹ã¯ä»¥ä¸ã®ãªã³ã¯å ã®ãªã³ã¯ããå ¥ãã®ãããããããã¾ãã.
https://gist.github.com/yutopp/d3a184f3389df819a5b4b99f2da9b774
Goroutine
æè¿äººæ°ã® Go ã¯ç°¡åã«ä¸¦åå対å¿ããããã°ã©ã ãæ¸ããã¨è¨ããã¦ãã¾ã. ããã¯
- ã³ã³ãã¤ã©ãé å¼µã£ã¦ãã: blocking 㪠API å¼ã³åºãã non-blocking ã«ãã¦ããã, å®è¡ãã¦ããã¿ã¹ã¯ã®åãæ¿ããã¦ã¼ã¶ã¼ããé è½ãã¦ãã. (ã®ã§, å¾æ¥çãªæ¸ãæ¹ã®ã¾ã¾ä¸¦åã«åä½ããããã°ã©ã ãæ¸ãæã.)
- MPG model: M:N ã¢ãã«ã® work stealing ã¹ã±ã¸ã¥ã¼ã©ãªã®ã§å°ãªãã¹ã¬ããã§å¹ççã«å¦çãã§ãã. (ä¸ã® Rust/tokio ã® blocking API ã®ä»çµã¿ãå èµãã¦ãã. èªåã§ãã£ã¦ãããã®ã§ã¦ã¼ã¶ã¼ã¯ç¹å¥ãªãã¨ãããªãã¦ããã.)
- netpoller: é »åºãããããã¯ã¼ã¯éä¿¡ã® API ã«ã¤ãã¦ã¯, epoll/kqueue ãå©ç¨ãã¦ãã. (OS ã¹ã¬ããæ°ãæããå¹æããã.)
- å¯å¤ã®ã¹ã¿ãã¯ãµã¤ãº
ã¨ããã®ã主ãªãã¤ã³ãã§ã.
(å ã¿ã«, Go 㯠stackful symmetric coroutine ã¨è¨ããã¨æãã¾ã. èªå㯠Go ã® runtime ã®ã½ã¼ã¹ã³ã¼ãèªãã§ãªãã®ã§ééã£ã¦ããããã§ãã.)
ä¸è¨ã¯ä»¥ä¸ã®è¨äºã§å¤§å¤ãããããã解説ããã¦ãããã, ããã§ã¯è§£èª¬ãã¾ãã.
- Golangã®ã¹ã±ã¸ã¥ã¼ã©ãããã®è©±
- The Go scheduler
- The Go netpoller
- goroutineã¯ãªã軽éãªã®ã
- Non-Blocking I/O, I/O Multiplexing, Asynchronous I/Oã®åºå¥
ããã, goroutine ã Rust ã«è¼¸å ¥ããã°ãããããªããã¨æãããããã¾ããã, Rust ãéè¦è¦ãã¦ãããã®ã¨åã¿åããªããã, ãã®ã¾ã¾ã§ã¯é£ããã®ã ã¨æãã¾ã.
- ã¦ã¼ã¶ã¼ã¬ãã«ã®ã¹ã¿ãã¯æä½: goroutine ã¯ããããã¹ã¿ãã¯ãæã£ã¦ãã, ã¿ã¹ã¯ã®åãæ¿ãã¯ããããåãæ¿ãããã¨ã§å®ç¾ããã. ããã«ã¯ã¢ã»ã³ãã©ã«ããã¹ã¿ãã¯æä½ãå¿
è¦.
- å¤ã㯠Rust ã«ããã®ç¨®ã®ãã®ããã£ãã, ãªããªã£ã.
- å¯å¤ã¹ã¿ãã¯ãµã¤ãºãèªåã§ã®ã¿ã¹ã¯åãæ¿ãã®ããã«ã¯, ã¦ã¼ã¶ã¼ãæ¸ããããã°ã©ã ä¸ã«ã³ã³ãã¤ã©ãå¥ã®å½ä»¤ãå·®ãè¾¼ãå¿
è¦ããã.
- OS ããã¢ã¡ã¿ã«ç¨éãè¦æ®ããé¢ä¿ä¸, ã³ã¼ãã¯æ¸ããããã®ãã®ã¾ã¾åä½ããã¹ã.
Rust ã§ã®æ¹é: async/await, Future, Pin, runtime, Waker
Rust ã®æ¹éã¯, ä¸è¨ã® Go ã®æ¹æ³ãä¸æãã㨠Rust æµã«è½ãè¾¼ãã ãã®ã ã¨è¦åããã¨ãã§ããã§ããã. (æççã«ãã追ã£ã¦ãªãã®ã§, ãããæå³ããã¦ãããã¯ç¥ãã¾ãã. ãåç¥ã®æ¹ããããæãã¦ãã ãã.)
表層ã¨ãã¦ã¯,
- async/await æ§æã Future ã«å¤æ.
- Future 㯠asymmetric stackless coroutine. ç¶æ æ©æ¢°ã¨ãã¦å®è£ å¯è½ãªã®ã§ä½ã³ã¹ã.
- Future ã¯åæå¯è½ãªã®ã§ asymmetric stackful coroutine æ¦å¿µãä½ãã.
- runtime ããããã管çãããã¨ã§ symmetric stackful coroutine ã®ããã«è¦åãã.
詳細:
- κeenã®Happy Hacκing Blog -- async/awaitã¨åæå¯è½æ§
- äºå±±æ¢åæ´å²é¤¨ -- Rustã¸ã§ãã¬ã¼ã¿å¾¹åºè§£èª¬
注æã§ãã, ããã¾ã§ãå¾ãã®ãµãã¤ã¯æ¦å¿µçã«ããè¦åããã¨ãã話ã§ã. symmetric/asymmetric ã stackful/stackless ã®å®ç¾©çã«ã¯å³å¯ã«ã¯éãã¨æãã¾ã.
ã¢ã»ã³ããªã§ã¹ã¿ãã¯ãã¤ã³ã¿ãåãæ¿ããã®ã, runtime ã Future ã poll ãã¦, æ»ã£ã¦ãã¦, å¥ã® Future ã poll ãã, ã¨ããã®ã§å®ç¾ãã¦ããããã§ãã.
ã¡ã¢ãªç®¡çã¨ãã¦ã¯,
- Future ã¯ç¶æ æ©æ¢°ãªã®ã§ãã¼ãã«ç¢ºä¿ããã°ããã¯ã.
- åé¡ã¨ãªãèªå·±åç §ã®ã±ã¼ã¹ã¯ Pin ãå°å ¥ãããã¨ã«ãã£ã¦è§£æ±º.
詳細:
ãã , æç´ã« Future ã poll ããã ãã ã¨, å®ã¯ã§ããä»äºããªãã®ã« CPU ãææ¾ããªãã¨ãããã¨ã«ãªã£ã¦ãã¾ãã¾ã. ããã解決ããã®ã Waker ã§ã.
(éã«è¨ãã¨) Waker 㯠Future ã poll ãã¦æ¬²ãããªã£ããå©ãã¹ã¤ããã§ãã, ãã㯠Go 㧠blocking 㪠goroutine ãåéå¯è½ã«ãªã£ãã¨ãã« global queue ã«å ¥ãåä½ã«ä¼¼ã¦ãã¾ã.
epoll/kqueue ã管çãã netpoller ã«å¯¾å¿ããã®ã, mio ãªã©ã®ã©ã¤ãã©ãªãªããã§ã. ãããã£ãã©ã¤ãã©ãªã¯ Waker ã®ã¤ã³ã¿ã¼ãã§ã¼ã¹ãå©ç¨ãã¦ã¿ã¹ã¯ã®å®è¡å¯å¦ã runtime ã«ä¼ãããã¨ã«ãªãã¾ã.
ã¾ã¨ã
- ãããããªéåæããã°ã©ãã³ã°ã¢ãã«ããã, ã¹ã¬ãããã¼ã«ãªã©åä½ã§ã¯ä¸åå.
- ã¦ã¼ã¶ã¼ããããã¨, éåæããã°ã©ãã³ã°ã¢ãã«ã¨ã㦠stackful coroutine ãæ±ãæã.
- Go ã®æ¹æ³ãåèã«ãªãã, ãã®ã¾ã¾ã§ã¯ Rust ã«å°å ¥ã§ããªã.
- async/await, Pin, Waker ãªã©ã«ãã, Go ã®ã¢ãã«ãä¸æã Rust ã«å°å ¥ãããã¨ãã§ãã. (ã¨è¦åãã.)
ä¸é£ã®è©±ã¯ Rust ã«å°å ¥ããã¨ãã話ã§ããã, å®ã¯ããã¯(OS ã¹ã¬ããã¯è§¦ãããã¢ã»ã³ããªã§å±ããã¨ã¯ã§ããªã/ããããªã)ä»ã®è¨èªã§ãå¯è½ã§ããã.
Common Lisp ã¯ããã«è©²å½ããè¨èªã§, å®éã«ãã£ã¦ã¿ããã¨æã£ã¦ã¾ã.
Rust Advent Calendar 2019, ææ¥ã¯ topecongiro ããã®äºå®ã§ã.