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
Fukuoka.rb_0x100_LT.pdf
Search
Sponsored
·
Ship Features Fearlessly
Turn features on and off without deploys. Used by thousands of Ruby developers.
→
Yusuke Iwaki
May 11, 2022
Technology
480
0
Share
Embed
Copy iframe code
Copy JS code
Copy link
Start on current slide
Fukuoka.rb_0x100_LT.pdf
Yusuke Iwaki
May 11, 2022
More Decks by Yusuke Iwaki
See All by Yusuke Iwaki
Playwrightのソースコードに見る、自動テストを自動で書く技術
yusukeiwaki
15
7.3k
あなたのWebサービスはAIに自動テストしてもらえる?アクセシビリティツリーで読み解く、AIの『視点』
yusukeiwaki
1
9.3k
個人開発から公式機能へ: PlaywrightとRailsをつなげた3年の軌跡
yusukeiwaki
12
9.2k
Capybara+生成AIでどこまで本当に自然言語のテストを書けるか?
yusukeiwaki
7
6k
ChatGPTを個々人が使っていた組織から チームチャットにボットを棲まわせて みんなが活用する組織になるまでの変遷 ぜんぶ紹介しちゃいます
yusukeiwaki
0
3.6k
E2E testing on Rails 2023
yusukeiwaki
4
3.6k
Railsの システムテスト解剖学
yusukeiwaki
8
8.2k
RailsのSystem specから 🎭Playwrightを使う
yusukeiwaki
2
16k
puppeteer-ruby: Ruby/Railsのためのブラウザオートメーションツール
yusukeiwaki
0
1.9k
Other Decks in Technology
See All in Technology
しろおびから始める!ログ活用の第一歩
shumei_ito
0
920
アウトプット初心者、半年間のふりかえり
4o1sobblue
0
200
go-sqletch
moznion
0
140
Kiro Crewをはじめよう
kizawa2020
1
150
組み立てて楽しむ AWS Blocks 入門
kmiya84377
0
230
Classmethod Company Deck
satoshi7
0
180
AIは「聞けば答える」から「任せると自分で進める」へ - JACTIMペナン地域部会・ペナン三水会講演
knishioka
0
110
無理せず続ける、子育てエンジニアの学び
codmoninc
PRO
0
720
宣言型部分更新は何を解決しどこへ向かうのか
shuta13
1
370
10年後、Engineering 行為を剥奪されるとして、わたしたちは、どう、何を創ればいいだろうか。 / If Engineering Is Taken Away in 10 Years, How and What Should We Create?
bitkey
PRO
1
160
Snapshot Testing in Practice: Predictable and Reliable SwiftUI Views
fespinoza
0
210
SREでアラート疲れを 解決しよう!
kairim0
1
230
Featured
See All Featured
Jess Joyce - The Pitfalls of Following Frameworks
techseoconnect
PRO
1
440
Paper Plane (Part 1)
katiecoart
PRO
2
11k
Designing for humans not robots
tammielis
254
26k
The Mindset for Success: Future Career Progression
greggifford
PRO
0
530
Winning Ecommerce Organic Search in an AI Era - #searchnstuff2025
aleyda
2
2.2k
4 Signs Your Business is Dying
shpigford
187
23k
How to optimise 3,500 product descriptions for ecommerce in one day using ChatGPT
katarinadahlin
PRO
3
3.9k
SEO for Brand Visibility & Recognition
aleyda
0
4.8k
Bootstrapping a Software Product
garrettdimon
PRO
306
120k
Leading Effective Engineering Teams in the AI Era
addyosmani
9
2.7k
The State of eCommerce SEO: How to Win in Today's Products SERPs - #SEOweek
aleyda
2
12k
SERP Conf. Vienna - Web Accessibility: Optimizing for Inclusivity and SEO
sarafernandez
2
1.6k
Transcript
async/await Rubyでどう書く? Fukuoka.rb 0x100 LT @YusukeIwaki
About @YusukeIwaki • 仕事:天神にある会社で、Railsアプリケーションの開発 ◦ 生まれは富山、大学は京都、1社目は札幌、2018年に福岡に移住 • puppeteer-rubyとかplaywright-ruby-clientとか作ってる人 ◦ ブラウザを自動操作するやつ
◦ Rubyでブラウザ操作するのに、Selenium以外の選択肢を作りたい。
Fukuoka.rb 0x0100回おめでとうございます • Kaigi on Rails 2021登壇のきっかけは、Fukuoka.rbの夜会 ◦ 夜の23時まで開いているRubyコミュニティは多分ここだけ? ◦
福岡にゆかりのあるひともないひともつながれるRubyコミュニティは素晴らしい ◦ 今後もゆるゆるとRubyを盛り上げていきましょう
本日の話 async / await ってRubyだとどうやって使えばいいの?
JSの有名ライブラリ Railsから使いたい! →Rubyに移植したい! async Promise then catch Promise.all Promise.race await
おそらく以下のどっちかが現実解 • 思考停止でconcurrent-rubyを使う ◦ とくにRailsアプリケーションだったら手軽 • めっちゃ考えてAsync gemを使う ◦ シングルスレッド動作で最大限のパフォーマンスが出せる
(memo) ここまで1分
おさらい: RubyのThreadとFiber • Thread→思考停止で、2つ以上の処理を同時に流せる • Fiber→ゆずりあいで、2つ以上の処理をかわりばんこに流す ◦ 合言葉は Fiber.yield
% ruby fiber.rb 0 1 2 3 4 0 1
2 3 4 % ruby thread.rb 0 0 1 1 2 2 3 3 4 4
async/await in Ruby • 思考停止でconcurrent-rubyを使う ◦ Threadベース ◦ とくにRailsアプリケーションだったら手軽 •
めっちゃ考えてAsync gemを使う ◦ Fiberベース ◦ シングルスレッド動作で最大限のパフォーマンスが出せる
(memo) ここまで2分半
concurrent-rubyでの async/await Promise Concurrent::PromisesモジュールのFutureを使う。 https://github.com/ruby-concurrency/concurrent-ruby/blob/master/docs- source/promises.in.md
concurrent-ruby: 2種類のFuture Concurrent::Promises.future { ….. ; 123 } • 裏で処理をやって、結果として123を返す
• Thread.newと同じ使い勝手で、さらに実行結果をもらえるイメージ f = Concurrent::Promises.resolvable_future, f.fulfill(123) , f.reject(err) • スレッドセーフな箱を作って、結果123を別スレッドから入れてもらう • JSのPromiseのような使い勝手
concurrent-ruby: Futureのチェーン、結果待ち受け future.then { |result| … ; next_result }.then {
|next_result| … } • JSのPromise#then, Promise#catch に限りなく近い future.value! • futureの結果をもらう。 • futureの結果がまだ出ていない場合には、結果が出るまでブロッキング。 Concurrent::Promises.zip(future1, future2, …) • 全部の結果が出揃うのを待つ。JSのPromise.allと同じ。
async click(x, y) { const point = await clickablePoint(x, y)
await scrollToPosition(x, y) await Promise.all([ mouse.down(x, y), mouse.up(x, y), ]) } def click(x, y) Concurrent::Promises.future do point = clickable_point(x, y).value! scroll_to_position(x, y).value! Concurrent::Promises.zip( mouse.down(x, y), mouse.up(x, y), ).value! end end concurrent-rubyを使ったasync/awaitっぽい実装 ※ 擬似コードです
でも気をつけろ!concurrent-rubyはThreadベースだ!
None
None
Async gem https://rubykaigi.org/2019/presentations/ioquatix.html
ノンブロッキングI/Oを活用し、IO待ちの間に別の処理を行う • シングルスレッドのFiberベースなので、オーバーヘッドが非常に少ない Ruby 2.xで利用するときには ノンブロッキングI/Oベースの各種ライブラリを併用する必要がある Async gem
Async { … } / Async::Reactor.run { … } •
処理のかたまり(task)を定義する ◦ JSの async () => { … } と似ている • トップレベルで利用するときと、ネストで利用するときとで挙動が違う ◦ トップレベルで利用時・・・サブタスクが全部終わるまで待つ ◦ ネストで利用時・・・サブタスクを作成し、スケジュール ◦ これも JSの async function呼び出しの挙動と似ている Async gemの基本
q = Async::Queue.new, q.dequeue, q.enqueue(hoge) • q.dequeueを呼ぶと、誰かがq.enqueueするまで待つ • q.dequeueよりも先に誰かがenqueue(hoge)していたら、即座にhogeが返る •
ほぼPromise cond = Async::Condition.new, cond.wait, cond.signal(hoge) • cond.waitを呼ぶと、誰かがcond.signalするまで待つ • cond.waitよりも先に誰かがcond.signal(hoge)しても、signalは捨てられる • 自前でPromiseっぽい何かを作る材料になる Async::Barrier, Async::Semaphore • サブタスク全部が終わるまで待つ、サブタスクの同時実行数を制限する • Promise.all 的なものを作る材料になる Async gemを使って async/await Promise
async click(x, y) { const point = await clickablePoint(x, y)
await scrollToPosition(x, y) await Promise.all([ mouse.down(x, y), mouse.up(x, y), ]) } def click(x, y) Async do point = clickable_point(x, y).wait scroll_to_position(x, y).wait barrier = Async::Barrier.new barrier.async { mouse.down(x, y).wait } barrier.async { mouse.up(x, y).wait } barrier.wait end end Async gemを使ったasync/awaitっぽい実装 ※ 擬似コードです
でも気をつけろ!Async gemはFiberベースだ! • 思考停止で使うと、並列処理されない(当然) • 不用意にwaitすると、メインスレッドがブロックされ全部が動かなくなる • Ruby 2.7で使いたいならノンブロッキングI/Oベースのライブラリ導入に そこそこ対応工数がかかる
ただ、用途があえば • すんごい速い • すんごい安定 ◦ 「ときどき処理順序がひっくり返ってしまって困る・・・」のような Threadベースだと起きる問題がFiberベースでは起きない
(memo) ここまで4分
まとめ:async/await in Rubyの現実解 • 思考停止でconcurrent-rubyを使う ◦ とくにRailsアプリケーションだったらもともと入ってるので手軽 ◦ Threadベースなので、処理順序性の保証とかほぼない •
めっちゃ考えてAsync gemを使う ◦ Fiberベースのシングルスレッド動作で最大限のパフォーマンスが出せる ◦ JSのasync functionに近い動作 ◦ Ruby 2.7環境で既存のアプリケーションに導入するのは結構たいへん
DEMO