strings.Builderとbytes.BufferのWrite系関数のベンチマーク

TL; DR 平均して見るとstrings.Builder#WriteXXXの方が速そう strings.Builder Go 1.10からstrings.Builder構造体が追加されました。 公式ドキュメントには、 A Builder is used to efficiently build a string using Write methods. It minimizes memory copying. The zero value is ready to use. Do not copy a non-zero Builder. と説明が書かれています。 おそらく、これまで文字列の組み立てをする際にはbytes.Bufferを使っている場合が多かったと思われますが、そういった目的の選択肢として作られたようです。 が、説明を読んでもいまいち違いがわかりません。 とりあえず、bytes.Bufferとstrings.Builderでは速度面で違いがあるのか調べるべく、ベンチマークを実施しました。 条件 実行した環境 MacBook Air MacOS Sierra 10.12.6 CPU: Core i7 1.7GHz メモリ: 8GB 実行する関数 Write WriteByte WriteRune WriteString exec 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 $ for i in {1..10}; do go test -bench . | tail -n +4 | head -n 8 && echo; done BenchmarkBuilderWrite-4 10000000 129 ns/op BenchmarkBuiderWriteByte-4 200000000 6.47 ns/op BenchmarkBuilderWriteRune-4 200000000 7.61 ns/op BenchmarkBuilderWriteString-4 30000000 92.4 ns/op BenchmarkBufferWrite-4 50000000 196 ns/op BenchmarkBufferWriteByte-4 300000000 9.40 ns/op BenchmarkBufferWriteRune-4 200000000 8.18 ns/op BenchmarkBufferWriteString-4 50000000 217 ns/op BenchmarkBuilderWrite-4 10000000 189 ns/op BenchmarkBuiderWriteByte-4 100000000 10.5 ns/op BenchmarkBuilderWriteRune-4 100000000 10.4 ns/op BenchmarkBuilderWriteString-4 30000000 157 ns/op BenchmarkBufferWrite-4 50000000 238 ns/op BenchmarkBufferWriteByte-4 100000000 19.9 ns/op BenchmarkBufferWriteRune-4 100000000 15.5 ns/op BenchmarkBufferWriteString-4 30000000 422 ns/op BenchmarkBuilderWrite-4 10000000 131 ns/op BenchmarkBuiderWriteByte-4 200000000 7.58 ns/op BenchmarkBuilderWriteRune-4 200000000 8.48 ns/op BenchmarkBuilderWriteString-4 30000000 113 ns/op BenchmarkBufferWrite-4 50000000 199 ns/op BenchmarkBufferWriteByte-4 100000000 10.4 ns/op BenchmarkBufferWriteRune-4 200000000 12.0 ns/op BenchmarkBufferWriteString-4 50000000 382 ns/op BenchmarkBuilderWrite-4 10000000 122 ns/op BenchmarkBuiderWriteByte-4 200000000 7.45 ns/op BenchmarkBuilderWriteRune-4 200000000 8.44 ns/op BenchmarkBuilderWriteString-4 30000000 155 ns/op BenchmarkBufferWrite-4 50000000 264 ns/op BenchmarkBufferWriteByte-4 200000000 7.08 ns/op BenchmarkBufferWriteRune-4 200000000 10.1 ns/op BenchmarkBufferWriteString-4 30000000 413 ns/op BenchmarkBuilderWrite-4 20000000 117 ns/op BenchmarkBuiderWriteByte-4 200000000 6.81 ns/op BenchmarkBuilderWriteRune-4 200000000 6.87 ns/op BenchmarkBuilderWriteString-4 50000000 219 ns/op BenchmarkBufferWrite-4 20000000 101 ns/op BenchmarkBufferWriteByte-4 200000000 6.22 ns/op BenchmarkBufferWriteRune-4 200000000 12.2 ns/op BenchmarkBufferWriteString-4 50000000 513 ns/op BenchmarkBuilderWrite-4 10000000 161 ns/op BenchmarkBuiderWriteByte-4 200000000 8.36 ns/op BenchmarkBuilderWriteRune-4 200000000 8.24 ns/op BenchmarkBuilderWriteString-4 30000000 109 ns/op BenchmarkBufferWrite-4 50000000 296 ns/op BenchmarkBufferWriteByte-4 100000000 10.6 ns/op BenchmarkBufferWriteRune-4 100000000 11.4 ns/op BenchmarkBufferWriteString-4 50000000 484 ns/op BenchmarkBuilderWrite-4 10000000 133 ns/op BenchmarkBuiderWriteByte-4 200000000 7.16 ns/op BenchmarkBuilderWriteRune-4 200000000 8.10 ns/op BenchmarkBuilderWriteString-4 30000000 194 ns/op BenchmarkBufferWrite-4 50000000 190 ns/op BenchmarkBufferWriteByte-4 200000000 5.51 ns/op BenchmarkBufferWriteRune-4 200000000 8.72 ns/op BenchmarkBufferWriteString-4 50000000 281 ns/op BenchmarkBuilderWrite-4 10000000 136 ns/op BenchmarkBuiderWriteByte-4 200000000 11.4 ns/op BenchmarkBuilderWriteRune-4 50000000 28.0 ns/op BenchmarkBuilderWriteString-4 10000000 119 ns/op BenchmarkBufferWrite-4 20000000 144 ns/op BenchmarkBufferWriteByte-4 100000000 16.0 ns/op BenchmarkBufferWriteRune-4 200000000 8.43 ns/op BenchmarkBufferWriteString-4 50000000 248 ns/op BenchmarkBuilderWrite-4 10000000 130 ns/op BenchmarkBuiderWriteByte-4 200000000 7.83 ns/op BenchmarkBuilderWriteRune-4 200000000 7.13 ns/op BenchmarkBuilderWriteString-4 30000000 99.0 ns/op BenchmarkBufferWrite-4 50000000 202 ns/op BenchmarkBufferWriteByte-4 200000000 10.7 ns/op BenchmarkBufferWriteRune-4 100000000 13.8 ns/op BenchmarkBufferWriteString-4 50000000 452 ns/op BenchmarkBuilderWrite-4 10000000 146 ns/op BenchmarkBuiderWriteByte-4 200000000 7.89 ns/op BenchmarkBuilderWriteRune-4 200000000 8.24 ns/op BenchmarkBuilderWriteString-4 30000000 122 ns/op BenchmarkBufferWrite-4 50000000 248 ns/op BenchmarkBufferWriteByte-4 100000000 31.7 ns/op BenchmarkBufferWriteRune-4 100000000 25.4 ns/op BenchmarkBufferWriteString-4 30000000 413 ns/op Source ベンチマークスクリプトのソースは以下の様になっています。 ...

2018-03-05 · nasa9084

Go言語で文字列を処理する

Go言語のregexpパッケージを使用した正規表現の処理は、一般的なスクリプト言語の処理速度と同程度で、正規表現を使用しない処理に比べてパフォーマンスがよくありません1。 そのため、可能であるならregexpパッケージを使用しないようにすべきです。 しかし、すべての処理を自分で書くのは大変です。 標準パッケージにも文字列を処理する関数が数多く用意されています。 strings パッケージ stringsパッケージはその名の通り、文字列を取り扱うパッケージです。 UTF-8でエンコードされた文字列(普通の文字列)をそのまま取り扱います。 判別系 Contains 1 func Contains(s, substr string) bool Contains関数は、sの中にsubstrが存在するかどうかを返します。 Pythonで言うところのsubstr in sに相当します。 正規表現ならば、substrとのmatchで真偽値をとることに相当します。 example 1 2 3 4 5 fmt.Println(strings.Contains("hogefugapiyo", "fuga")) // Output: true fmt.Println(strings.Contains("hogefugapiyo", "foo")) // Output: false ContainsAny 1 func ContainsAny(s, chars string) bool ContainsAny関数はsの中に、charsに含まれる文字のいずれかが存在するかどうかを返します。 つまり、charsは文字列ですが、扱いとしては文字の配列であると考えた方が良いでしょう。 正規表現で表すなら、/[${chars}]/の様な表現と考えられます(${chars}は置き換える)。 example 1 2 3 4 5 fmt.Println(strings.ContainsAny("hogefugapiyo", "abcd")) // Output: true fmt.Println(strings.ContainsAny("hogefugapiyo", "1234")) // Output: false HasPrefix 1 func HasPrefix(s, prefix string) bool HasPrefix関数は、sの頭がprefixと等しいかどうかを判別します。 正規表現で^を使った文字列マッチに相当します。 Prefixなのでマッチさせたい文字列をつい第一引数に与えたくなりますが、第二引数がPrefixです。 example 1 2 3 4 5 fmt.Println(strings.HasPrefix("hogefugapiyo", "hoge")) // Output: true fmt.Println(strings.HasPrefix("hogefugapiyo", "piyo")) // Output: false HasSuffix 1 func HasSuffix(s, suffix string) bool HasSuffix関数は、HasPrefix関数と対になる関数で、sの末尾がsuffixと等しいかどうかを判別します。 正規表現で$を使った文字列マッチに相当します。 ...

2018-03-05 · nasa9084

YAPC::Okinawa 2018 ONNASONに行ってきました

YAPC::Fukuoka 2017 HAKATA (行ってきたときの記事はこちら )に引き続き、YAPC::Okinawa 2018 ONNASON に行ってきました。 YAPCはPerlのイベントで、“Yet Another Perl Conference"の略です。twitterハッシュタグは前回に引き続き#yapcjapan でした(#yapcokinawa もよく使われていたようです)。 沖縄は昨年6月にOSC 2017 Okinawa で行って以来二度目です。 YAPC当日はすごい雨で、YAPC::Hokkaidoで大雪だったことを思い出し、「端っこでYAPCをやると何かが起きるのでは」などと言われる具合でした。 今回は直前までホテルが取れなかったものの、過去のYAPCでホテルを取らずに行って適当になんとかなったので、なんとかなるだろうと思っていましたが、直前に東横インを確保できたので、宿無し旅行ではありませんでした。 YAPC::Okinawa 2018 ONNASON 今回は会場がOIST だったため(OISTは那覇市内から車で約一時間)、多くの人がスタッフが手配した往復バスでの参加となりました。 そのため、寝坊する人は少なく(いなくはなかったようです)、私もオープニングから参加できました。 オープニングはCodeHex 氏。 オープニングを行ったA会場は非常に広く、なんと全席にコンセントがついているという素晴らしいホールでした。 ノベルティはこんな感じ。特筆すべきはDeNAさんのQi充電器でしょうか。しかし私はQi対応端末を持っていないので使えないのが残念・・・・ 毎度恒例、ネコトーストラボさんのサイリュームもあります。 YAPC::Hokkaidoから行われてきたチェックインスタンプラリーもココで一区切り。 コンプリート特典として、JPAのラクダさんのシャチハタスタンプをいただきました。 トークでは、「レイヤー0(電波)からレイヤー8(交渉事)までできる人を募集しています」や、「無曖昧でない」など、会場がどっと沸く名言(迷言?)がいくつか飛び出ました。 個人的には、@moznionさん のInlineモジュールの話や、新屋さん の正規表現の話が非常に面白かったと思います。 特に、正規表現の話ではバックトラックと曖昧な正規表現の相性が悪い、といった技術的な話にとどまらず、文脈自由文法など、計算理論にまで踏み込んだトークとなっており、OISTという会場でのトークに相応しい素晴らしい内容だったと思います。 次回のお話 次回YAPCは東京 だそうです!現在はまだテザーサイトがある程度で、日程、会場は調整中とのことでした。

2018-03-04 · nasa9084

cut vs. parameter expansion

TL;DR:: bash/zsh parameter expansion is faster than cut. which is faster? Consider you want to take out hostname from URL or IP with port like some.mysql.server:3306 or 192.168.1.10:3306 using bash/zsh. There are some way to do this. The first way is using cut command: 1 2 $ TARGET="192.168.1.10:3306" $ echo ${TARGET} | cut -d ":" -f 1 Now printed 192.168.1.10 on your screen. The second way is using “shell parameter expansion”, which is functions of bash/zsh built-in. You can use shell parameter expansion like below: ...

2018-02-26 · nasa9084

Goでコマンドラインオプションを処理する

TL;DR github.com/jessevdk/go-flagsが便利 flagパッケージ コマンドライン・ツールを作ろうと考えたとき、避けては通れないのがコマンドラインオプションを如何に処理するか、ということです。 Go言語では、標準パッケージにflagというパッケージが存在し、これを用いることでコマンドラインオプションをパースすることが出来ます。 しかし、flagパッケージでは、ロングオプションとショートオプションを一度に定義することが出来ず、また、ロングオプションであろうとショートオプションであろうと-XXXという、ハイフンが一つつく形式のオプションとなります。 これはあまり一般的ではなく1、便利とも言いにくいでしょう。 そこで便利なのが、jessevdk/go-flags パッケージです。 go-flagsパッケージ jessevdk/go-flags パッケージは、その名の通り、コマンドラインオプションを取り扱うパッケージです。 ショートオプション、ロングオプションはもちろんのこと、ショートオプションをまとめて指定する、同じオプションを違う引数で複数回指定する、環境変数からの読み込み、デフォルト値の指定などに対応していて、一般的なオプションの処理に幅広く対応出来ます。 オプションは構造体として定義出来るため、パースした後の処理で取り回すのも簡単です。 簡単な例を見てみましょう。 1 2 3 4 5 6 7 8 9 10 11 12 type options struct { Name string `short:"n" long:"name" description:"listen address"` } func main() { var opts options if _, err := flags.Parse(&opts); err != nil { // some error handling return } fmt.Printf("Hello, %s\n", opts.name) } パッケージ宣言やインポートの節は省略していますが、上記をmain.goとして実行すると、以下の様に出力されます。 1 2 3 4 5 6 7 8 9 10 11 12 $ go run main.go -h Usage: main [OPTIONS] Application Options: -n, --name= listen address Help Options: -h, --help Show this help message $ go run main.go -n Foo Hello, Foo フィールドの設定 jessevdk/go-flagsパッケージでは、オプションを定義するために構造体を作ります。 構造体の各フィールドがオプション一つ一つに当たります。 そのため、細かい設定はタグで行うことになります。 以下で、このパッケージで使用できる、主なタグを紹介します。 ...

2018-02-24 · nasa9084

kubesprayを使用してkubernetes clusterを構築する(2)

3ヶ月ほど前に、kubesprayを使用してkubernetes clusterを構築する という、kubespray とkubespray-cliを使用してKubernetesクラスタを構築する記事を書きました。 しかし、kubespray-cliはすでにdeprecatedだということなので 、kubespray-cliを使用せずにkubesprayでクラスタを構築する手順をまとめておきます。 要件 kubesprayを使用してkubernetesクラスタを構築するための要件は以下のようになっています。 ansible 2.4以降とpython-netaddr (python-netaddrを忘れがちなので注意) pip install ansible netaddr Jinja 2.9以降(ansibleの依存でインストールされると思います) 構築先サーバがインターネットに接続できること 構築先サーバでswapが無効化されていること 構築先サーバでIPv4 forwardingが有効になっていること sysctl -w net.ipv4.ip_forward=1する(再起動するまで) /etc/sysctl.confにnet.ipv4.ip_forward = 1と記入する(再起動後) Ansibleを実行するマシンから構築先サーバにSSH鍵が渡されていること ファイアウォールが無効化されていること ファイアウォールの設定をしっかりできる人は有効でも また、kubesprayには(kubespray-cliのような)inventory生成ツールが付属されており、これを利用する場合はpython3系である必要が有ります。 構成 前回の記事同様、以下のIPを持った三台のサーバを対象として構築してみます。 192.168.1.11 192.168.1.12 192.168.1.13 それぞれ、IPv4 forwardingが有効化され、firewalldを無効化し、Python 3をインストール済みのCentOS 7のサーバとします。また、kubesprayを実行するローカルマシンから、各サーバのrootユーザにSSH鍵を配置1済みとします。 手順 準備 まず、kubesprayをダウンロードします。 1 2 $ git clone https://github.com/kubernetes-incubator/kubespray $ cd kubespray リポジトリのクローンが完了したら、ansibleなどの依存モジュールを導入します2。 1 kubespray$ pip install -r requirements.txt 次に、ansible用のインベントリを作成します。 1 2 3 kubespray$ cp -rfp inventory/sample inventory/mycluster kubespray$ declare -a IPS=(192.168.1.11 192.168.1.12 192.168.1.13) CONFIG_FILE=inventory/mycluster/hosts.ini python3 contrib/inventory_builder/inventory.py ${IPS[@]} IPSは対象サーバのIPに合わせて定義をします。 また、環境によっては、python3コマンドではなく、pythonコマンドでPython 3が実行される場合も有ります。適宜読み替えてください。 ...

2018-02-23 · nasa9084

Generates LICENSE file: git-license

When we create a new repository on GitHub , we can choose an open source license. We choose an OSS license, then, LICENSE file is put into the new repository. Now, I’m usually using hub command to create a new repository. I’ll do below to create: 1 2 3 4 5 6 7 8 $ mkdir my_new_repository $ cd my_new_repository $ git init # # ... some code writing and commit ... # $ git create # git command is aliased to hub $ git push -u origin master In this flow, I can write description for repository1, set homepage2, make the repository private3, but I CANNOT choose LICENSE. I can choose and create LICENSE file on the GitHub web page, or I can copy from my other repositories because its content is fixed. However, I don’t do that. ...

2018-02-21 · nasa9084

テキストを列ごとにそろえて出力する

TL;DR: 標準パッケージtext/tabwriter を使用する コマンドラインツールで標準出力を良い感じにそろえて出力したい場合があります。 例えば、docker では、以下の様に出力されます。 1 2 3 4 $ docker container ls CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES 8caad461b4a4 redis "docker-entrypoint.s…" 5 days ago Up 5 days 0.0.0.0:6379->6379/tcp redis-svr 329c9f9be035 mysql "docker-entrypoint.s…" 5 days ago Up 5 days 0.0.0.0:3306->3306/tcp mysql-svr このような map、あるいは構造体の配列 の様なものを、きれいに表形式の様に列をそろえて出力したい場合に便利なのが標準パッケージのtext/tabwriter です。 その名の通り、タブ区切りの文字列を良い感じに出力してくれるパッケージです。 text/tabwriterで定義されているのはいくつかの設定用定数 と、Writer構造体 のみです。 Writerは(勿論)io.Writerインターフェース を実装しています。 使用方法は通常のio.Writerとはすこし変わっていて、最初にWriter.Init() で初期化し、任意回数Writer.Write() で書き込みをした後、Writer.Flush() で整形した文字列を出力します。 NewWriter() 関数はWriter構造体をnew()した後Init()するのと同等です。 Writer.Init()関数及びNewWriter()関数に与える引数は以下の様になっています。 名前 型 内容 output io.Writer Flush()したときの出力先 minwidth int 1セルあたりの最小幅(パディングを含む) tabwidth int タブ文字の幅(スペースの個数と等しい) padding int パディング1 padchar byte パディング文字2 flags int 調整用フラグ 最後の引数である、調整用フラグには0(標準状態)を与えるか、パッケージ定数 の論理和を用いて設定を与えます。 ...

2018-01-29 · nasa9084

Vagrant/vmware-fusionでハードウェア仮想化を有効にしたVMを作成する

vmware fusionを使用している場合、仮想マシンのCPU設定でこの仮想マシンでハイパーバイザアプリケーションを有効にするにチェックを入れることで仮想マシン内でKVMを動作させることができるようになります。 ドキュメントには載っていませんが1、Vagrant + vmware-fusion pluginの構成でも設定することが可能です。 Vagrantfileに以下の記述を追加します。 1 2 3 config.vm.provider "vmware_fusion" do |v| v.vmx["vhv.enable"] = "TRUE" end vmxの設定をする方法自体は公式ドキュメント にも記載がありますが、詳細がありません ↩︎

2017-12-28 · nasa9084

container-upというツールを書いた

container-up というツールを書いたのでご紹介。 背景 このブログはghost というブログエンジンで動いています。動作環境としてDocker を使用していて、Ghostの公式イメージ を使用しています。 過去の経緯から、単体のDockerコンテナで動作させており、永続データはDockerボリュームとしてマウントしている形です。 扨、Docker ComposeやKubernetesなどのオーケストレーションツールを使っている場合、コンテナのバージョンアップは比較的簡単に行うことができます。 たとえば、Docker Composeを使用している場合、docker-compose upで、新しいイメージで作成したコンテナに差し替えることができます。 しかし、Dockerを単体で使っている場合、基本的には手作業で差し替えを行う必要があります。 Ghostコンテナの更新時は手作業でBlue-Greenアップグレードを行ってきたのですが、Ghostはかなりアップデートのペースが速く、毎度コンテナを差し替えるのが面倒になってきました。 それを楽にするため、container-upを作りました。 インストール Go環境がある人 Go言語の環境がすでにある人は、以下のコマンドで使用できるようになります。 1 $ go get github.com/nasa9084/container-up それ以外の人 Go言語の環境がない人は、Releases ページから自分のOSに併せてバイナリをダウンロード、パスを通してください。 windows, linux, macos向け、それぞれamd64版のバイナリを用意してあります。 動作確認はmacos、linux(CentOS 7)のみ行っています。 これら以外の環境の人は、予めdep をインストールした上で以下のコマンドでコンパイルしてください。 1 2 3 4 $ git clonse https://github.com/nasa9084/container-up.git $ cd container-up $ dep ensure $ go build -o container-up main.go コンパイルしたら、任意の場所にバイナリを移動し、パスを通してください。 使い方 基本的な使い方は、引数にコンテナ名またはコンテナIDを渡すだけです。 1 $ container-up CONTAINER_NAME 与えられたコンテナと同じ名称のイメージを使用して、ボリュームやネットワークなどの設定はそのままに新しいコンテナを作成し、差し替えます。 :latestなイメージを使用している場合、docker pullした後にこのコマンドを実行することで、最新のイメージから作られたコンテナに差し替わるということです。 もとのコンテナは--rmオプションをつけて起動していた場合を除いて、_oldContainerというサフィックスが付いた状態でstopします。 なにか問題があった場合は、このコンテナに戻すと良いでしょう。 もし、元のコンテナが必要ない場合は、--rmオプションをつけると、差し替え時に削除します。 1 $ container-up --rm CONTAINER_NAME :latestではないような、バージョンタグが付いたイメージを使用していて、新しいバージョンのイメージを使いたい場合などのため、新しいイメージ名を指定して実行することもできます。 ...

2017-12-22 · nasa9084