15
16

More than 5 years have passed since last update.

Crystalで並行化する方法: 6秒かかる処理を3秒にしよう

Last updated at Posted at 2015-08-07

この記事の目的

6秒かかる直列処理を並行処理に改修し、3秒で終わるようにする

準備

まずは、適当にフォルダを作る

mkdir ~/Desktop/crystal
cd ~/Desktop/crystal/

つぎに、main.crファイルを作る

vim main.cr

まず直列実行するプログラムを書く

  • 1秒待つコマンド
  • 2秒待つコマンド
  • 3秒待つコマンド

上記を順番に実行していくプログラムを main.cr の中身を書く。
つまり、合計で6秒かかってしまう。

main.cr
require "logger"

log = Logger.new(STDOUT)

log.info "started."

# 1秒かかるコマンド
log.info "sleep1 started."
sleep 1
log.info "sleep1 finished."

# 2秒かかるコマンド
log.info "sleep2 started."
sleep 2
log.info "sleep2 finished."

# 3秒かかるコマンド
log.info "sleep3 strated."
sleep 3
log.info "sleep3 finished."

log.info "all finished."

ともあれ、実行してみる

% crystal run main.cr
I, [2015-08-07 18:21:57 +0900 #9884]  INFO -- : started.
I, [2015-08-07 18:21:57 +0900 #9884]  INFO -- : sleep1 started.
I, [2015-08-07 18:21:58 +0900 #9884]  INFO -- : sleep1 finished.
I, [2015-08-07 18:21:58 +0900 #9884]  INFO -- : sleep2 started.
I, [2015-08-07 18:22:00 +0900 #9884]  INFO -- : sleep2 finished.
I, [2015-08-07 18:22:00 +0900 #9884]  INFO -- : sleep3 strated.
I, [2015-08-07 18:22:03 +0900 #9884]  INFO -- : sleep3 finished.
I, [2015-08-07 18:22:03 +0900 #9884]  INFO -- : all finished.

やはり、6秒かかった。

これを並行化したい。

spawnを使って並行化し、3秒で終わるようにする

Crystal言語には、Go言語のgoのように処理を簡単に並行にできるspawnがある。

ただし、spawnだけでは、並行化した処理が終わる前に、メインの処理が終わってしまう。つまり、待ってくれない。各処理が終わるまで待つには、ChannelというAPIを使う。

なお、各ルーチンの実行結果を、呼び出し元に戻すときにもチャネルを使う。今回は、特に実行結果は必要ないので、チャネルに適当な値を入れることにする。ここでは、とりあえずbool値にする。

以上を踏まえて、さきほどの main.cr を改修する:

main.cr
require "logger"

log = Logger.new(STDOUT)

log.info "started."

channel = Channel(Bool).new

# 1秒かかるコマンド
spawn do
  log.info "sleep1 started."
  sleep 1
  log.info "sleep1 finished."
  channel.send true
end

# 2秒かかるコマンド
spawn do
  log.info "sleep2 started."
  sleep 2
  log.info "sleep2 finished."
  channel.send true
end

# 3秒かかるコマンド
spawn do
  log.info "sleep3 strated."
  sleep 3
  log.info "sleep3 finished."
  channel.send true
end

# 終わるまで待つ
3.times do
  channel.receive
end

log.info "all finished."

実行してみよう

% crystal run main.cr
I, [2015-08-07 18:34:31 +0900 #10590]  INFO -- : started.
I, [2015-08-07 18:34:31 +0900 #10590]  INFO -- : sleep3 strated.
I, [2015-08-07 18:34:31 +0900 #10590]  INFO -- : sleep2 started.
I, [2015-08-07 18:34:31 +0900 #10590]  INFO -- : sleep1 started.
I, [2015-08-07 18:34:32 +0900 #10590]  INFO -- : sleep1 finished.
I, [2015-08-07 18:34:33 +0900 #10590]  INFO -- : sleep2 finished.
I, [2015-08-07 18:34:34 +0900 #10590]  INFO -- : sleep3 finished.
I, [2015-08-07 18:34:34 +0900 #10590]  INFO -- : all finished.

並行化ができて、3秒で終わるようになった\(^o^)/

まとめ

6秒かかる処理を、spawnChannelを組み合わせて並行化し、3秒で終わるようになった。

関連

Goルーチンで並行化する方法: 6秒かかる処理を3秒にしよう - Qiita

更新

[2015-08-07]
Crystalの作者の @asterite さんから「終わるまで待つ」部分をもっとシンプルに書けると教えていただきました。ありがとうございます!

15
16
1

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
15
16