初めに
Goのすごい人がついったーでgophernotes の pure go zeromq 対応が入った。
とツイートしてた。
すごい人が言ってるんだから使っておいて損無いハズ。
5分ぐらい考えた結果、FizzBuzzすることに決めた。
プログラマならFizzBuzzとか数列とか使いたくなるんだからしょうがない。
できたもの
斬新なFizzBuzz結果
zeromqとは
ブローカーなしのメッセージング。ブローカー不要が何より嬉しい。
どうせ通信相手そんなにいないのに、いちいちサーバ立てたくない。
詳しくはZeroMQ参照。
FizzBuzzとは
よくやる奴。割愛。
【非検証】gophernotesを使おうとしたけど使えなかったので手順だけまとめる
gophernotesとは、Jupyter NotebookのGo言語版的な奴。詳しくはgophernotesを参照。
諸般の事情(Windowsしか持ってない)があるので、Dockerを利用する必要がある。
が、今現在Dockerが利用できる端末がない。
なので環境構築の順番だけでもまとめる。
簡単に利用するためにgopherdata/gophernotesをベースとして自分の使いやすいイメージを作る。
Dockerfile
FROM gopherdata/gophernotes:latest
RUN go get github.com/go-zeromq/zmq4 \
&& mkdir -p /etc/jupyter
COPY ./entrypoint.sh /entrypoint.sh
COPY ./jupyter_notebook_config.py /etc/jupyter/jupyter_notebook_config.py
ENTRYPOINT [ "/entrypoint.sh" ]
entrypoint.sh
jupyter notebook --no-browser --allow-root --ip=0.0.0.0 --config=/etc/jupyter/jupyter_notebook_config.py
configはgopherdata/gophernotesのイメージをいったん走らせてから、コンテナに吐いてもらう。
# コンテナ走らせて中に入る
docker run -it -d gopherdata/gophernotes
docker exec -it ${gophernotesのid} /bin/sh
# config吐く
jupyter noteboopk --generate-config
mv /path/to/jupyter_notebook_config.py /tmp/
exit
# ローカルに落とす
docker cp ${gophernotesのid}:/tmp/jupyter_notebook_config.py ./
手元で試すだけなら、jupyter_notebook_config.pyのtokenを書き変える。
後はコンテナをビルドして実行するだけ
docker build -t miyatamagophernotes:1.0.0 .
docker run -it -p 8888:8888 miyatamagophernotes:1.0.0
zmq4
まずはpub側から
publish側
1秒おきに100までのFizzBuzzを垂れ流す。
package main
import (
"fmt"
"time"
"context"
"sync"
"github.com/go-zeromq/zmq4"
)
func main() {
err := startPublisher()
if err != nil {
fmt.Printf("%v", err)
}
}
func startPublisher() error {
pub := zmq4.NewPub(context.Background())
defer pub.Close()
err := pub.Listen("tcp://*:5563")
if err != nil {
return err
}
for {
publishFizzBuzz(pub)
if err != nil {
return err
}
time.Sleep(time.Second)
}
return nil
}
func publishFizzBuzz(publisher zmq4.Socket) {
getFizzBuzzText := func(num int) string {
if (num % 15) == 0 {
return "FizzBuzz"
}
if (num % 3) == 0 {
return "Fizz"
}
if (num % 5) == 0 {
return "Buzz"
}
return fmt.Sprintf("%d", num)
}
wg := &sync.WaitGroup{}
for i := 0; i < 100 ; i++ {
wg.Add(1)
go func(number int) {
defer wg.Done()
msg := zmq4.NewMsgFrom(
[]byte("FizzBuzz"),
[]byte(getFizzBuzzText(number)),
)
publisher.Send(msg)
}(i + 1)
}
wg.Wait()
}
続いてsub
Subscribe側
受け取って表示するだけ
package main
import (
"context"
"fmt"
"github.com/go-zeromq/zmq4"
)
func main() {
err := startSubscribe()
if err != nil {
fmt.Printf("%v", err)
}
}
func startSubscribe() error {
sub := zmq4.NewSub(context.Background())
defer sub.Close()
err := sub.Dial("tcp://localhost:5563")
if err != nil {
return err
}
err = sub.SetOption(zmq4.OptionSubscribe, "FizzBuzz")
if err != nil {
return err
}
for {
msg, err := sub.Recv()
if err != nil {
return err
}
fmt.Printf("%s\n", msg.Frames[1])
}
}
ふりかえり
今回も様々な知見を得られた
- FizzBuzzをgophernotes上のZeroMQでやる必要は全くない
- gophernotesが利用できなかったので単純にzmq4でFizzBuzzしただけになった
- 並列処理したおかげでFizzBuzzの結果が正しいかよく分からなくなった