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
ffi & native extension
Search
atomiyama
October 17, 2019
Programming
280
0
Share
Embed
Copy iframe code
Copy JS code
Copy link
Start on current slide
ffi & native extension
heiseirb9
atomiyama
October 17, 2019
More Decks by atomiyama
See All by atomiyama
SchemaDrivenDevelopment
atomiyama
0
480
Rustでgemを作ろう
atomiyama
0
1.7k
技術選定で失敗したはなし
atomiyama
0
1.4k
はじめてのDocker
atomiyama
0
120
Other Decks in Programming
See All in Programming
作れる、でも消せるか?──安全に「枯らして消す」機能削除術 / Drain, Then Delete
chobishiba
2
890
AmebaブログはKMPから卒業します
kmars0605
0
220
Railsバージョンを4倍にした話
optim
0
520
AI時代のコードレビューは人に向けるな、仕組みに向けろ
texmeijin
5
3.7k
S3 TablesのIcebergデータに、AIエージェントからアクセスしてみた / 20261016developersio2026joetsu-accessing-iceberg-in-s3tables-via-agent
kasacchiful
PRO
0
190
Atomic Design, Enforced: Scaling Mobile Design Systems (next.app devCon / droidCon Berlin 2026)
steliosf
PRO
0
180
contenteditable と日本語入力に向き合う
colorful12
0
210
残高管理から台帳サービスへの進化
artoy
1
210
[2026-10-09]一枚の布で作らなくてもいい。 信頼性は「パッチワーク」で紡がれる~既存の運用と新しい可能性をつなぎ合わせてきたCREの話~
tosite
0
110
IBM Bob でAI駆動開発『QC-Playbook』
ichirokano2
0
120
PumaからFalconに移行したRailsアプリケーションでの実践
falcon8823
0
190
AWSに止められる覚悟してますか?
morizo_1984
2
540
Featured
See All Featured
How to Get Subject Matter Experts Bought In and Actively Contributing to SEO & PR Initiatives.
livdayseo
0
220
Information Architects: The Missing Link in Design Systems
soysaucechin
1
1.2k
The Limits of Empathy - UXLibs8
cassininazir
2
730
Unsuck your backbone
ammeep
672
58k
Principles of Awesome APIs and How to Build Them.
keavy
128
18k
Jess Joyce - The Pitfalls of Following Frameworks
techseoconnect
PRO
1
450
Conquering PDFs: document understanding beyond plain text
inesmontani
PRO
4
3.2k
The Web Performance Landscape in 2024 [PerfNow 2024]
tammyeverts
12
1.3k
DBのスキルで生き残る技術 - AI時代におけるテーブル設計の勘所
soudai
PRO
68
59k
Chrome DevTools: State of the Union 2024 - Debugging React & Beyond
addyosmani
10
1.4k
Everyday Curiosity
cassininazir
0
360
Designing for Timeless Needs
cassininazir
1
530
Transcript
FFI & Native Extension 1
github.com/atomiyama/heiseirb9 2
whoami Akifumi Tomiyama Studyplus Inc, H3.12.16 server-side enginner github: @atomiyama
Twitter: @atomiyama1216 3
好きな⾔語はなんですか? 4
Rust & Ruby 5
RubyからRustを呼んでみたい 6
why 早いらしい 低レイヤの⾔語書いてみたかった => それを好きなRubyから呼べたら楽しそう 7
Rubyから他の⾔語を呼び出す⽅法 FFI (Foreign Function Interface) Native Extension 8
FFI (foreign function interface) ⾊々な⾔語で定義された関数とかをRubyから呼べるようにしてくれる. => Rustなりから作成した共有ライブラリの関数シンボルとシグネチャーをRubyスクリプトか ら渡すことでRustの関数を呼び出せるように橋渡しをしてくれる. ただ引数の型, 戻り値の型といった関数シグネチャーの情報は与えてあげる必要があるので使
いたい数が増えればRuby側もそれなりの記述量になるしRustで書いてRubyでも書くってちょ っと違う. 9
Native Extension (拡張ライブラリ) Rubyからは普通のライブラリと同じようにrequireするたけで呼び出せる. => ruby-ffiでやっていたような橋渡しのような役割も記述する必要があって rb_define_method などのAPIを使ってRubyを拡張してあげる必要がある.こちらのほうが 圧倒的に記述量は多いように感じるけどRuby側から関数シグネチャー渡したりしなくてよい のいい.
10
こんにちは世界! Rustで適当に関数を定義 // hello_world.rs #[no_mangle] pub extern fn hello_world() {
println!("Hello World, I am Rust!"); } コンパイルしてdylibファイル⽣成 $ rustc --crate-type="dylib" hello_world.rs # 関数シンボルが存在するか確認する $ nm libhello_world.dylib | grep hello_world 0000000000000f10 T _hello_world 0000000000090b60 S _rust_metadata_hello_world_8787f43e282added376259c1adb08b80 11
ffiでrubyから関数を呼び出す require 'ffi' module RustEx extend FFI::Library ffi_lib "libhello_world.dylib" attach_function
:hello_world, [], :void end pp RustEx::hello_world #=> "Hello World, I am Rust!" 12
ほんとに早くなってるのか 13
Rust Tutorialにあるやつ 14
10個のスレッドで500万までカウントするコード threads = [] 10.times do threads << Thread.new do
count = 0 5_000_000.times do count += 1 end count end end threads.each do |t| puts "Thread finished with count=#{t.value}" end puts "done!" 15
Rustで書く(ffi) #![crate_type="dylib"] use std::thread; #[no_mangle] pub extern fn process() {
let handles: Vec<_> = (0..10).map(|_| { thread::spawn(|| { let mut x = 0; for _ in 0..5_000_000 { x += 1 } x }) }).collect(); for h in handles { h.join().unwrap(); }; } 16
Rubyから呼ぶ require 'ffi' module FFIEx extend FFI::Library ffi_lib './liblib.dylib' attach_function
:process, [], :void end pp FFIEx.process 17
計測してみる require "./ffi/main" require "./purerb/main" require "benchmark/ips" Benchmark.ips do |x|
x.report "Ruby Func" do PureRuby.process end x.report "Rust Func" do FFIEx.process end x.compare! end 18
早い!!! $ ruby benchmark.rb Warming up -------------------------------------- Ruby Func 1.000
i/100ms Rust Func 1.000 i/100ms Calculating ------------------------------------- Ruby Func 0.526 (± 0.0%) i/s - 3.000 in 5.709806s Rust Func 1.232 (± 0.0%) i/s - 7.000 in 5.684935s Comparison: Rust Func: 1.2 i/s Ruby Func: 0.5 i/s - 2.34x slower 19
Native Extension #![allow(non_snake_case)] extern crate libc; use std::ffi::CString; use std::thread;
type VALUE = libc::c_ulong; extern { fn rb_define_module(name: *const libc::c_char) -> VALUE; fn rb_define_module_function(module: VALUE, name: *const libc::c_char, value: extern fn(), argc: libc::c_int) -> libc::c_void; } extern fn rb_process() { let handles: Vec<_> = (0..10).map(|_| { thread::spawn(move || { let mut x = 0; for _ in 0..5_000_000 { x += 1 } x }) }).collect(); for h in handles { h.join().unwrap(); }; } #[no_mangle] // Init_{filename} の関数がエントリポイントになる // e.g. hoge.bundle をruby でrequire したらInit_hoge がエントリポイントになる pub extern fn Init_rustex() { let module_name = CString::new("RustEx").unwrap(); let process = CString::new("process").unwrap(); unsafe { let rb_cRustEx = rb_define_module(module_name.as_ptr()); rb_define_module_function(rb_cRustEx, process.as_ptr(), rb_process, 0); } } 20
呼ぶ # ./target/debug/librustex.dylib が作成される $ cargo build # macOS ではDynamic
Linking とDynamic Loading が明確に区別されていてruby からrequire するときはDynamic Loading が必要なので.bundle に変更しています $ mv target/debug/librustex.dylib rustex.bundle require "./rustex.bundle" RustEx.process 21
終わり 22