マルチスレッドなふぃずばずお嬢様
スクラップで整理した内容を記事化。
FizzBuzzをマルチスレッドで実施して、かつふぃずばずお嬢様にしてみた。
マルチスレッドな処理について
Gleamの本家TOPページにある、「multi_threaded_hello_world」を参考にして実施する。
まずは、プロジェクト作成。
$ gleam new multi_threaded_fizzbuzz
Your Gleam project multi_threaded_fizzbuzz has been successfully created.
The project can be compiled and tested by running these commands:
cd multi_threaded_fizzbuzz
gleam test
gleam/otpを利用できるようにする
マルチスレッドには、gleam/otp/processを利用する。
そして、gleam/otp/processを利用するには、モジュールgleam_otpを追加する。
これによって、erlangのotpが利用可能となる。
モジュールの追加には、gleam add
コマンドを利用する。
$gleam add gleam_otp
Resolving versions
Downloading packages
Downloaded 2 packages in 0.05s
Added gleam_otp v0.4.0
このコマンドを実行すると、gleam.toml
ファイルのdependencies
の項目に、gleam_otp
が追加されている。
~(略)~
[dependencies]
gleam_stdlib = "~> 0.22"
gleam_otp = "~> 0.4"
~(以下略)~
FizzBuzzについて
FizzBuzz関数の実装。
ひとまず、mainとは別のファイルにして実装。
import gleam/int
pub fn to_fizzbuzz(i) {
case i % 3, i % 5 {
0, 0 -> "FizzBuzz"
0, _ -> "Fizz"
_, 0 -> "Buzz"
_, _ -> int.to_string(i)
}
}
ついでにテストコードも書いとく。
テスト対象(今回の場合、fizzbuzz/fizzbuzz
)を明示的にimport
しないといけないのがちょっと気になるところ。
import fizzbuzz/fizzbuzz
import gleeunit/should
pub fn to_fizzbuzz_test() {
fizzbuzz.to_fizzbuzz(1)
|> should.equal("1")
fizzbuzz.to_fizzbuzz(3)
|> should.equal("Fizz")
fizzbuzz.to_fizzbuzz(5)
|> should.equal("Buzz")
fizzbuzz.to_fizzbuzz(15)
|> should.equal("FizzBuzz")
fizzbuzz.to_fizzbuzz(40)
|> should.equal("Buzz")
fizzbuzz.to_fizzbuzz(42)
|> should.equal("Fizz")
fizzbuzz.to_fizzbuzz(43)
|> should.equal("43")
fizzbuzz.to_fizzbuzz(45)
|> should.equal("FizzBuzz")
}
gleam test
コマンドで、テストを実行してみる。
$gleam test
Compiling multi_threaded_fizzbuzz
Compiled in 1.33s
Running multi_threaded_fizzbuzz_test.main
..
Finished in 0.016 seconds
2 tests, 0 failures
お嬢様の語尾について
何をすれば「ふぃずばずお嬢様」になるのかよくわかっていないので、とりあえず語尾をお嬢様っぽくしてみることにした。
FizzBuzzに利用する数値が、奇数なら「ですわ〜」、偶数なら「ですのよー」 を出力することにした。
ひとまずは、fizzbuzz/fizzbuzz
へ関数を用意することにした。
〜(上記略)〜
pub fn to_gobi(i) {
case int.is_odd(i) {
True -> "ですわ〜"
False -> "ですのよー"
}
}
テストコードも追記。
〜(上記略)〜
pub fn to_gobi_test() {
fizzbuzz.to_gobi(1)
|> should.equal("ですわ〜")
fizzbuzz.to_gobi(2)
|> should.equal("ですのよー")
fizzbuzz.to_gobi(8)
|> should.equal("ですのよー")
fizzbuzz.to_gobi(9)
|> should.equal("ですわ〜")
}
gleam test
を実行。こちらも、とくに問題なし。
$gleam test
Compiling multi_threaded_fizzbuzz
Compiled in 1.23s
Running multi_threaded_fizzbuzz_test.main
...
Finished in 0.018 seconds
3 tests, 0 failures
メイン処理
最初にふれたgleam/otp/process
を利用してマルチスレッドを実施する。
メイン処理中で、今回作成した「FizzBuzz」と「語尾」を組み込む。
import gleam/io
import gleam/int
import gleam/list
import gleam/string
import gleam/otp/process
import fizzbuzz/fizzbuzz
pub fn main() {
list.range(1, 100)
|> list.map(start_process)
|> list.map(process.monitor_process)
|> list.each(process.receive(_, 3))
// Wait for them to finish
}
fn start_process(i) {
process.start(fn() {
let fizzbuzz_msg = fizzbuzz.to_fizzbuzz(i)
let gobi_msg = fizzbuzz.to_gobi(i)
let message =
string.concat([int.to_string(i), " は ", fizzbuzz_msg, gobi_msg])
io.println(message)
})
}
gleam run
で実行。以下のような結果を得た。
$gleam run
Compiling multi_threaded_fizzbuzz
Compiled in 1.47s
Running multi_threaded_fizzbuzz.main
1 は 1ですわ〜
2 は 2ですのよー
99 は Fizzですわ〜
4 は 4ですのよー
20 は Buzzですのよー
40 は Buzzですのよー
41 は 41ですわ〜
42 は Fizzですのよー
43 は 43ですわ〜
44 は 44ですのよー
45 は FizzBuzzですわ〜
〜(略)〜
コード一式
ひとまず、ソースコード一式を記載する。
import gleam/io
import gleam/int
import gleam/list
import gleam/string
import gleam/otp/process
import fizzbuzz/fizzbuzz
pub fn main() {
list.range(1, 100)
|> list.map(start_process)
|> list.map(process.monitor_process)
|> list.each(process.receive(_, 3))
// Wait for them to finish
}
fn start_process(i) {
process.start(fn() {
let fizzbuzz_msg = fizzbuzz.to_fizzbuzz(i)
let gobi_msg = fizzbuzz.to_gobi(i)
let message =
string.concat([int.to_string(i), " は ", fizzbuzz_msg, gobi_msg])
io.println(message)
})
}
import gleam/int
pub fn to_fizzbuzz(i) {
case i % 3, i % 5 {
0, 0 -> "FizzBuzz"
0, _ -> "Fizz"
_, 0 -> "Buzz"
_, _ -> int.to_string(i)
}
}
pub fn to_gobi(i) {
case int.is_odd(i) {
True -> "ですわ〜"
False -> "ですのよー"
}
}
import fizzbuzz/fizzbuzz
import gleeunit/should
pub fn to_fizzbuzz_test() {
fizzbuzz.to_fizzbuzz(1)
|> should.equal("1")
fizzbuzz.to_fizzbuzz(3)
|> should.equal("Fizz")
fizzbuzz.to_fizzbuzz(5)
|> should.equal("Buzz")
fizzbuzz.to_fizzbuzz(15)
|> should.equal("FizzBuzz")
fizzbuzz.to_fizzbuzz(40)
|> should.equal("Buzz")
fizzbuzz.to_fizzbuzz(42)
|> should.equal("Fizz")
fizzbuzz.to_fizzbuzz(43)
|> should.equal("43")
fizzbuzz.to_fizzbuzz(45)
|> should.equal("FizzBuzz")
}
pub fn to_gobi_test() {
fizzbuzz.to_gobi(1)
|> should.equal("ですわ〜")
fizzbuzz.to_gobi(2)
|> should.equal("ですのよー")
fizzbuzz.to_gobi(8)
|> should.equal("ですのよー")
fizzbuzz.to_gobi(9)
|> should.equal("ですわ〜")
}
まとめ
ただFizzBuzzを書くのも面白みがなかったので、お嬢様口調にしてみましたわ。
余談ですが、range
の範囲を「range(1,10000)」で試したみたら、3000あたりまでしか動作しなかった。
どこかでストッパーになっている関数があるのかな。別途調べてみよう。
。。。ではなくて、調べてみますわ。
Discussion