More Related Content
Similar to Thread の利用事例紹介
Similar to Thread の利用事例紹介 (20)
More from Tomoya Kawanishi
More from Tomoya Kawanishi (15)
Thread の利用事例紹介
- 2. Meguro.rb #16 発表資料 「Thread の利用事例紹介」
1自己紹介
Tomoya Kawanishi a.k.a. @cuzic
エネチェンジ株式会社 チーフエンジニア
電力会社、ガス会社を切り替えるなら、エネチェンジ経由で!
一般家庭も!法人も!
Ruby関西の中の人
7月21日に 大阪Ruby会議01 を開催予定
大手町.rb の中の人
次回、7月10日(火)Otemachi.rb #8 の開催を予定
東京駅、各線大手町駅から直結!
テーマは「Dir、File、IO」
Ruby の初級者がメインターゲット
- 3. Meguro.rb #16 発表資料 「Thread の利用事例紹介」
おさらい
meguro.rb #8 での発表
tsort について
AWS の費用を事業ごとの分配をするために、
AWS リソースをタグ付け
内部的には、aws コマンドを繰り返し実行
実行結果を元にグラフ構造を構築
トポロジカルソートを行う tsort ライブラリを利用
グラフ構造を元に、EC2 のタグをほかのリソースに展開
2
EC2 EBS
スナップ
ショット
AMI
ENI EIP
- 4. Meguro.rb #16 発表資料 「Thread の利用事例紹介」
もっと速くしたい
実行してみたところ、わりと時間がかかった
5分くらい
もっと速くしたい!
aws コマンドの実行に時間を要しているのは明らか
aws コマンドを並列実行するともっと速くできる!
3
- 5. Meguro.rb #16 発表資料 「Thread の利用事例紹介」
処理内容
遅いのは、AWS リソースの情報取得のところと、
タグ付のところ
特に、タグ付のところが遅かった
4
グラフ構造の構築
トポロジカルソート
AWS リソースのタグ付
AWS リソースの情報取得
(AWS コマンドの発行)
AWS コマンドを 4回発行
describe-instances
describe-network-interfaces
describe-images
describe-snapshots
AWS コマンドを リソースの数、
タグの数に応じて、繰り返し実行
- 6. Meguro.rb #16 発表資料 「Thread の利用事例紹介」
情報取得(メインスレッド側)
Threadを使った内部実装は意識させない設計
引数: aws コマンドの引数
ブロック引数: aws コマンドの実行結果(標準出力)の各行
Thread#join を各スレッドで実行。情報取得終了を待つ
5
def each_ebs_snapshot
query = "Snapshots[].[VolumeId, SnapshotId]"
aws_lookup(%(ec2 describe-snapshots --query "#{query}")) do |line|
volume_id, snapshot_id = line.chomp.split("¥t")
yield volume_id, snapshot_id
end
end
ワーカスレッドで
実行される
def join_lookup_threads
@lookup_threads.each &:join
end
呼び出すとき
各スレッドの終了を待つとき
@lookup_threads は
ワーカスレッドの配列
- 7. Meguro.rb #16 発表資料 「Thread の利用事例紹介」
AWSリソースの情報取得(ワーカスレッド側)
スレッド内では Thread.new の引数だけを使用
そのスレッド内でのローカルコピーが作られる
他のスレッドでの更新が原因での不具合とかが起きない
aws コマンドを実行し、出力結果を1行ごとに
ブロック引数として呼び出し元に渡す
1つのコマンドを1つのスレッドで実行
あとで待ち合わせするため Thread を配列に保持
6
def aws_lookup(command)
@lookup_threads << Thread.new(command) do |cmd|
cmdline = "aws #{cmd} --output text"
IO.popen(cmdline, "r+") do |io|
io.each_line do |line|
yield line
end
end
end
end
Thread 中で使う
command を引数と
している
- 8. Meguro.rb #16 発表資料 「Thread の利用事例紹介」
タグ付(メインスレッド側)
タグ付けでは、異なるリソースを対象に繰り返し AWS
コマンドを発行する
ワーカスレッドで、AWSコマンドを並行実行する
スレッド間通信には Queue を使用する
Ruby 2.3以降は組み込みライブラリ
Queue#enq を利用
出力結果は使用しない
AWSコマンドの成功/失敗も気にしない(Fire and Forget)
複数リソースに対するタグ付けを1回で処理
shellwords ライブラリの Array#shelljoin メソッドを使用
7
def create_tags(resources, tags)
return if tags.empty?
args = ["--resources", resources.shelljoin, "--tags", tags.shelljoin]
@aws_queue.enq %(ec2 create-tags #{args.shelljoin})
end
- 9. Meguro.rb #16 発表資料 「Thread の利用事例紹介」
AWS リソースのタグ付(ワーカスレッド側)
Queue#deq で、キューからオブジェクトを取り出せる
while command = queue.deq は Thread 処理でよく使うイデ
ィオム
nil 以外の場合、ループの中の処理を行う
nil を受け取るとループから抜ける
8
def start_aws_thread
Thread.start do |t|
while command = @aws_queue.deq
cmdline = "aws #{command}"
system cmdline
end
end
end
end
nil 以外の場合はループの中を実行
nil のときは、ループを抜ける
- 10. Meguro.rb #16 発表資料 「Thread の利用事例紹介」
タグ付(メインスレッド側) 開始と終了
ワーカスレッドを開始すると、配列に保持する
ワーカスレッドを終了するため、nil を Queue に渡す
それぞれの Thread が終了するのを join で待つ
9
# ワーカスレッドの開始
def start_tagging_threads
@thread_num.times do
@tagging_threads << start_aws_thread
end
end
# ワーカスレッドの終了
def join_tagging_threads
@thread_num.times do
@aws_queue.enq nil
end
@tagging_threads.each &:join
end
スタートしたスレッドを配列に保持
ワーカスレッドの数だけ nil をキューに送信
ワーカスレッドの終了を join で待つ
- 11. Meguro.rb #16 発表資料 「Thread の利用事例紹介」
まとめ
AWS のリソースへのタグ付を例に
簡単な Thread の使い方を説明しました
キャラの違う2つの利用例で説明しました
リソース情報取得では、
1個のコマンドを1個の Thread で実行
外部コマンドの出力結果を利用する
Thread の start 時の引数だけを Thread 内で利用する
タグ付処理では
複数のコマンドを、複数の Thread で実行
外部コマンドの出力結果は利用しない。(単に捨てる)
Queue でコマンドの受け渡しをする
みなさまの開発のときにお役に立てると嬉しいです
10