名前:
瀬戸 啓一朗
経歴:
東大法学部卒業
2019年 楽天入社
k8sを触ることが多いですが
業務ではRuby (Rails)を使っています
とあるAさんのBさんのコードに対するReviewにて
Rubyでどんなコードを書くと
スレッドセーフじゃなくなるかが分からなかった
プロセス:
別のプロセスは別のプロセスのメモリを直接参照できない
スレッド:
メモリを共有しながら処理を行う
スレッドセーフとは
スレッドを同時並行で実行しても問題がない状態
じゃあ逆にスレッドセーフじゃないと何が起きる?
メモリ
スレッド1
スレッド2
本題
クライアントは果物をランダムな数だけ籠に入れてサーバーにpost
サーバーのレスポンスと自ら計算した値が合っているか計算し、
合っていたら ■
間違っていたら■
を標準出力
require 'net/http'
require 'json'
begin
prices = {
orange: 100,
apple: 200,
peach: 400
}
http = Net::HTTP.new('localhost', '3000')
loop do
items = [
{ name: :orange, count: rand(10) },
{ name: :apple, count: rand(10) },
{ name: :peach, count: rand(10) }
]
right_answer = items.sum do |item|
prices[item[:name]] * item[:count]
end
req = Net::HTTP::Post.new('/calc/index')
req.body = { items: items }.to_json
res = http.request(req)
print res.body.to_i == right_answer ? "\e[32m" : "\e[31m"
print "■\e[0m"
end
rescue Interrupt
puts 'good bye'
end
class CalcController < ApplicationController
protect_from_forgery
def index
Basket.init
JSON.parse(request.body.read)["items"].each do |item|
Basket.add(item["name"], item["count"])
end
render json: Basket.result
end
end
class Basket
@@total = 0
def self.init
@@total = 0
end
def self.add(name, count)
@@total += Item.find_by(name: name).price * count
end
def self.result
@@total
end
end
クライアント側から受け取ったリクエストをパースして籠に追加して結果を返す
@@totalというクラス変数にDBから取得した価格を用いて合計額を計算
(なんか怪しい実装w)
app serverは
マルチスレッドのpuma
GIL(グローバルインタプリタロック)
CRubyのスレッドはGILという機能により1つのプロセスでは複数のスレッドが同時に動かない
※JRubyとかだとガチでマルチスレッドで動きます
GILはIO時に解放されるそうで外部コマンドを呼び出したり、DBを叩いたり、HTTPでアクセスしたり等の間はマルチスレッドが有効です。
例えば、1回10秒かかるリクエストを4回したいときに、シングルスレッドだと40秒かかりますが、マルチスレッドだと10秒で終わります。