20200118のGoに関する記事は6件です。

Goclipse "could not start goclipse because java version is 0"

はじめに

Goclipseの設定でハマったので記録を残しておきます。

動作確認環境

OS:
macOS Mojave Version 10.14.6 (18G84)

STS:
Spring Tool Suite 4
Version: 4.5.0.RELEASE
Build Id: 201912171052

1. 余計なファイルを削除

https://github.com/GoClipse/goclipse/issues/256
にWorkaroundが記載されていたので、やってみた所、プラグインが起動するようになりました。

Note that the error message is not true, Goclipse does start successfully despite what the message says, so you can just keep using it. As a workaround, locate the plugins directory in the Eclipse installation, and delete the com.googlecode.goclipse.jvmcheck_1.0.0.v201607061938.jar file, this will prevent the error message from being shown.

STSを使っていたので、以下のPATHにありました。
/Applications/SpringToolSuite4.app/Contents/Eclipse/plugins/com.googlecode.goclipse.jvmcheck_1.0.0.v201607061938.jar

でも、使用感がイマイチだったので結局Goclipse自体を使うのは断念しました。。。

参考URL:
https://github.com/GoClipse/goclipse/issues/256

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

golangの並行処理のための言語要素に対応するCSPの記述を理解して形式検証の実践を開始しよう(検証編:クリティカルセクション)

image.png

はじめに

単純ですが具体的な例を示したいと思います。今回題材とするのは、「クリティカルセクション問題」です。これは並行処理のプログラムが資源を共有したりする場合に出くわす問題です。

今回、検証に使うツールはモデル検査ツールPAT(Process Analysis Toolkit)とします。利用の際にところどころツールの画面などができますが、ツールそのものの使い方の詳細は省かせていただきます。もちろん、同等の機能を持つ別なツールを使っても同様の検証が可能です。

クリティカルセクション問題

この問題は並行動作する2つのスレッドに対して、以下の要求が満たされているアルゴリズムを構成することです。

  • 要求1 : 排他制御。あるスレッドがクリティカルセクションを実行中は他のスレッドのクリティカルセクションを実行する事はできない。
  • 要求2 : あるスレッドがクリティカルセクション以外の処理を実行している場合には他のスレッドはいつでもそのクリティカルセクションを実行できる。

この2つの要求を満たすアルゴリズムはすでにいくつか知られているものがあります(Dekker's Algorithmなど)。しかし、本記事では、そのような完成したプログラムではなく、道半ばで上記の要求を満たしていないGo言語のプログラムを示し、それを形式言語であるCSPで記述し、検証する方法を説明します。

なお、今回の検証は要求1に絞って説明する事にします。

コード例: 要求1がNG - 同時に2つのThreadのクリティカルセクションが動作可能になってしまう

go言語での記述

各スレッドの定義(コード片)を載せます。

var Thread0inside int = 0;
var Thread1inside int = 0;

func ThreadZero() {
  for {
    for Thread1inside == 1 {}
    Thread0inside = 1;
    CriticalSectionZero()
    Thread0inside = 0;
    OtherStuffZero();
  }
}

func ThreadOne() {
  for {
    for Thread0inside == 1 {}
    Thread1inside = 1;
    CriticalSectionOne()
    Thread1inside = 0;
    OtherStuffOne();
  }
}

それぞれのスレッドは、まず、相手のスレッドがクリティカルセクションに入っているかどうかを確認します。入っていないないならクリティカルセクションに入りますが入っている間はそこにとどまります(ロック)。クリティカルセクションに入っているかどうかはそれぞれのスレッドが持つフラグの値を確認します。
と、一見、特に問題はなさそうですが・・

動かして確認したい人のために

また、当然ながらここに示したコード片だけでは、実行して確認する事はできません。このプログラムを確認するには以下の追加コードが必要になります:

  • 各スレッドの「無限ループ」を有限にする
  • 定義されていない関数を定義する

    • CriticalSectionZero(),CriticalSectionOne(),OtherStuffZero(),OtherStuffOne()はここを実行している事わかるような表示を行うようなものにする(fmt.Printfを使うなど)。
  • main関数を作る

    • mainの中でThreadZero()とThreadOne()をgo routineとして起動
    • 2つのThreadが終了するのに十分なWaitを行う(time.Sleepなどを利用)

goのコード(参考程度にどうぞ)

https://gist.github.com/fujim2/dc3625b8f20fc5eb40c3fb91e3d15356
critical_bad.go の各スレッドのsleepをコメントアウトすると2つのスレッドのクリティカルセクションが重なって実行されるのが観測できます。

CSPでの記述と検証

上記プログラムをCSPで記述してみます。

var Thread0inside  = 0;
var Thread1inside  = 0;

ThreadZero() = 
    [!(Thread1inside == 1)]
    T0Start
    ->CriticalSectionZero{Thread0inside = 1}
    ->T0End{Thread0inside = 0}
    ->OtherStuffZero
    ->ThreadZero();

ThreadOne() = 
  [!(Thread0inside == 1)]
   T1Start
    ->CriticalSectionOne{Thread1inside = 1}
    ->T1End{Thread1inside = 0}
    ->OtherStuffOne
    ->ThreadOne();

System = ThreadZero() || ThreadOne();

プログラミング言語に対応するCSPでの表現にはいくつかバリエーションがあるのですが、今回はできるだけコードと対応が付くようなものにしてみました。

状態の遷移空間を確認してみる

多くの「モデル検査ツール」は、「検査」の機能だけでなく、シミュレーションの機能を持っている事が多いです。ここでは、PATのシミュレーション機能を使って、このプログラムの振る舞いの空間を可視化してみます。

image.png

なかなか複雑ですね。この中のどこかに問題(要件を満たさない状況)があったとしても、なかなか見つけるのは大変かもしれません。

検証

さて、モデル検査ツールの本領を発揮してもらいましょう。以下の様なPATの検証式を使って検証します。今回は、モデル検査でよく使われる「時相論理式(temporal logic)」を使った検証は行わず、ツールの方ですでに用意されているものを使います。

検証式

以下の様な検証式を使って検証したいと思います。

#assert System deadlockfree;
#define badstatus (Thread0inside==1 && Thread1inside == 1);
#assert System reaches badstatus;

1行目はそもそも、Systemがデッドロックしないという検証式です。
2行目は2つのスレッドが同時にクリティカルセクションに入っているという「bad status」の定義です
3行目はSystemがこのbadstatusという状態に到達する可能性がある、という検証式です。

2つの検証式はの結果を確認してみます。PATでは、検証のための画面で検証式を選択し、「verify」というボタンを押すことで検証が開始し、結果はコンソールに表示されます。結果、

  • 1つ目の検証式はVALIDでした。つまり「デッドロックしない」事が検証できました。
  • 2つ目の検証式もVALIDでした。つまり、badstatusになるという事ですから問題がある、という指摘です。

image.png

2つ目の検証式は「到達可能性(reachability)」を検査したのですが、ツールは、検査結果を確認した後に、「Simulate Witness Trace」というボタンを押すことで、シミュレーション機能と連動して、パスを表示してくれます(検証の機能とシミュレーションの機能が連動しています)。

image.png

左側の表示エリアにはステップ毎の変数の値などが表示されていますが、Thread1insideとThread0insideの値がともに1になっている事(クリティカルセクションが同時に実行されている)がわかります。

CSPのコード(参考程度にどうぞ)

https://gist.github.com/fujim2/26afdf75cb84b01b144ac031546f1943

なお、このプログラムの問題が、これだけかどうかはこの時点ではわかりません。

さいごに

ここで示したプログラムコードは非常に小さいものですが、それでも、思ったようにはつくれない、それが「並行・並列」プログラミングの難しさです。そして、その原因の多くは並行に動作するために起こる動作タイミングの非決定性、そしれそれに関係して肥大している振る舞い空間にあると思います。このおかげで、往々にしてプログラムは直観に反する振る舞いの経路をたどって、思いもよらない不具合を引き起こします。

なお、本記事の題材は、「並列コンピューティング技法 - 実践マルチコア/マルチスレッドプログラミング(Clay Breshears著)」訳本の第3章「正当性の検証と性能測定」の例を参考にしました(コード・文書ともにコピペなどはしておりません)。

今回は以上です。では。

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

VSCodeでGo Toolsにビルドタグを渡す方法

背景

VSCodeのGo拡張を使用している際、異なるビルドタグを持ったファイルにある変数や関数等を参照しようとするとコード補完が上手く働かずundeclaredになってしまいます。これはLanguage Serverであるgopls1がタグ無しの状態で参照しているため起こる事象なのでタグを渡してあげる必要があります。

lib_util.go
// +build test

package lib

var (
    testUtil = "test util"
)
lib.go
package lib

import (
    "fmt"
)

func p() {
    fmt.Println(testUtil) // undeclared name: testUtil
}

対処法

settings.json に以下のような形で追記してやることでgoplsを含む各種Go Toolsにビルドタグを渡せます。プロジェクト毎に変更したい場合はWorkspaceレベルで設定してやると良いでしょう2

適用後はVSCodeを再起動するかF1メニューから "Developer: Reload Window" する必要があります(私の環境では "Go: Restart Language Server" だと上手くいきませんでした)。

    "go.toolsEnvVars": {
        "GOFLAGS": "-tags=test"
    },

参考文献

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

IntellijでGolangやるときの設定Tips

Gakuです。
Intellijで新規Golang PJを作成した際、いつも忘れるので、自分用の備忘録として残しておきます。

go rootの設定(必須)

Preference > Language & Frameworks > Go > GOROOT

image.png
でGOROOTを設定する。

go modを有効にする

pj rootフォルダで

gakumbp:ddd-golang gaku$ go mod init
go: creating new go.mod: module github.com/gaku3601/ddd-golang

上記を実行し、go.modを作成する。
Go Modulesの設定をしていないと、実行は可能だがコードがエラーの状態になってしまう。
image.png

Preference > Language & Frameworks > Go > Go Modules(vgo)
で以下のように設定する。
image.png

これで、コードのエラーがなくなる。

自動fmt、自動imports

Preferences > Tools > File Watchers
の+でgo fmt・goimortsを選択
image.png

これで自動フォーマット、自動importが効くようになる

linter

Preferences > Tools > File Watchers
でgolangci-lintを選択
go.modをpj root以外に設定している場合、Working directoryをgo.modが配置している場所と同じところを指定する。
image.png
lintが効くようになる。
image.png

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

スクリプト言語の比較しながらGoのお勉強 〜 環境構築編(MacOS)

ごあいさつ

はじめまして。@kuroseetsと申します。
2000年からフリーランスで仕事を始め開発12年、インフラ8年経験してきたオッサンです。
皆さんはどのプログラミング言語、スクリプト言語が好きですか?または仕事などで何をよく使っていますか?
開発をされている方だとJavaが多いのかな?またはC#?Ruby?PHP?
事務系でスクリプトを組む方などはVBScriptなども現役ですよね。
私は現在インフラ運用構築側にいますので、私を含めて周辺でよく使われているのが、Python, Ruby, Perl, Bash辺りが多く、最近ではさらにGolangが増えてきている印象です。(あくまで個人的主観で、ですよ
それぞれ好みはあるとは思いますが、環境や現場による制約で使えるもの使えないものがありまして、私もその都度現場でキャッチアップしてスキルを身に付けてきました。
現在ではInfrastructure as Codeと謳われるだけあって、構成管理の設定ファイル以外でも手を動かすことも増えてきたと身を以て感じています。
今回個人的にGolangを勉強しようと思っているのですが、折角なので勉強ついでに有名なスクリプト言語を比較してみようかなと思います。
対象はGolangの他、Python, Ruby, Perl, Bash(インフラ運用4強スクリプト!)を予定しています。


環境構築

使うからには最新版を使いたい!
ということで常に最新版をインストールしやすく、また管理しやすくするためにバージョン管理ツール越しにインタプリタをインストールすることにしました。

anyenvのインストール

@rinpa さんの https://qiita.com/rinpa/items/81766cd6a7b23dea9f3c を参考にしてインストールしました。
各スクリプト言語を使用するのにenv系コマンドは非常に便利なのですが、個別にインストールすると面倒です。
が、anyenvで一元管理できたら非常に便利ですね。

# anyenvインストール
brew install anyenv

# anyenvが実行できるか確認
anyenv --version

# 初期ディレクトリがないので初期化して作成
anyenv install --init

# インストールできるenv系コマンドの確認
anyenv install -l

# 各envをインストール
anyenv install goenv
anyenv install pyenv
anyenv install rbenv
anyenv install plenv

# 環境変数の設定
echo 'eval "$(anyenv init -)"' >> ~/.bash_profile
source ~/.bash_profile

golang

golangの最新版のインストールはgoenvに従って粛々と進めていきます。

# インストール可能なgoのバージョンを確認
goenv install -l

# 最新版をインストール(執筆時は1.13.6)
goenv install 1.13.6

# インストールしたバージョンを指定
goenv global 1.13.6

# 指定したバージョンが実行できているか確認
go --version

python

pythonも同様に最新版をインストールします。

# インストール可能なpythonのバージョンを確認
pyenv install -l

# 最新版をインストール(執筆時は3.8.1)
pyenv install 3.8.1

# インストールした最新版バージョンを指定
pyenv global 3.8.1

# 指定したバージョンが実行できているか確認
python --version

ruby

rubyも同じ手順です。

# インストール可能なrubyのバージョンを確認
rbenv install -l

# 最新版をインストール(執筆時は2.7.0)
rbenv install 2.7.0

# インストールした最新版バージョンを指定
rbenv global 2.7.0

# 指定したバージョンが実行できているか確認
ruby --version

perl

そしてperlも。

# インストール可能なrubyのバージョンを確認
plenv install -l

# stableの最新版をインストール(執筆時は5.30.1)
plenv install 5.30.1

# インストールした最新版バージョンを指定
plenv global 5.30.1

# 指定したバージョンが実行できているか確認
perl --version

bash

anyenvにはbashのバージョンを管理するツールがありませんので、下記のツールを利用させて頂きました。
https://i-beam.org/2015/12/25/211817/

サイトを参考にインストールしてみましたがエラーが出ました

git clone https://github.com/ueokande/bashvm ~/.bashvm
echo 'source $HOME/.bashvm/bin/bashvm-init' >> ~/.bashrc
source ~/.bashrc

  readlink: illegal option -- f
  usage: readlink [-n] [file ...]

BSD系のMacはreadlink-fオプションがないみたいですね
こちらを参考にreadlink -fするコマンドを作成
https://stackoverflow.com/questions/1055671/how-can-i-get-the-behavior-of-gnus-readlink-f-on-a-mac

cat << 'EOF' > /usr/local/bin/readlinkf
#!/bin/sh

TARGET_FILE=$1

cd `dirname $TARGET_FILE`
TARGET_FILE=`basename $TARGET_FILE`

# Iterate down a (possible) chain of symlinks
while [ -L "$TARGET_FILE" ]
do
    TARGET_FILE=`readlink $TARGET_FILE`
    cd `dirname $TARGET_FILE`
    TARGET_FILE=`basename $TARGET_FILE`
done

# Compute the canonicalized name by finding the physical path 
# for the directory we're in and appending the target file.
PHYS_DIR=`pwd -P`
RESULT=$PHYS_DIR/$TARGET_FILE
echo $RESULT
EOF
chmod 755 /usr/local/bin/readlinkf

readlink -fしているところをこのコマンドに置き換えます

--- bashvm-init.bak 2020-01-18 07:08:43.000000000 +0900
+++ bashvm-init 2020-01-18 07:09:30.000000000 +0900
@@ -124,7 +124,7 @@
 export -f bashvm

 export BASHVM_HOME=${BASHVM_HOME:-$HOME/.bashvm}
-PATH="$(readlink -f $(dirname $BASH_SOURCE)):$PATH"
+PATH="$(readlinkf $(dirname $BASH_SOURCE)):$PATH"

 test -f $BASHVM_HOME/config && source $BASHVM_HOME/config
 export bashvm_default_version=${bashvm_default_version:-system}

改めてsource ~/.bashrcを実行すると成功しました
ではbashの最新版をインストールします

# 執筆次の最新は5.0
bashvm install 5.0

# インストールした最新版バージョンを指定
bashvm use 5.0

# 指定したバージョンが実行できているか確認
bash --version

以上で構築作業は完了です。
次回から各言語を比較しながらプログラミングしていきます。

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

インフラ構築あるあるをGoで解決する!

Goにはまってるインフラエンジニアです。インフラ構築あるあるをGoで解決したいと思ってます。

背景

その昔のワタシと後輩の電話
※後輩は現地のマシンルーム、ワタシは事務所にいました。

後輩:コマンド間違えました!よくわからんコトになってます!
ワタシ:よくわからんって何や!ログ見て!
後輩:マシンルーム圏外やから外から電話してます!ログ見れないっす!
ワタシ:とりあえずSSHでログ見るか...
ワタシ:何やったのかさっぱりわからぬ\(^o^)/
ワタシ:現地行くか....

ってことがよくありましたね。こういうときのミスない遠隔HELPって何かできないかな〜と思って、
chatサーバ作るぜ!って思いました。

巷にはwebsocketを使ったchatはあったのですが、↑みたいな場面ってSSHしかできないようなケースあるんで、
普通のsocketで作りました。あまり先行事例がなくて、結構ムズかったです。ゴルーチンとチャネルが難しい....

超絶参考にさせていただきました↓
https://blog.logicky.com/2017/06/16/go-%E3%83%81%E3%83%A3%E3%83%83%E3%83%88%E3%82%A2%E3%83%97%E3%83%AA%E3%82%92%E3%81%A4%E3%81%8F%E3%81%A3%E3%81%A6%E3%81%BF%E3%81%9F/

感想

slackすげーなって本当に思いました。
作り終わったあと、プログラミング言語Go読んだら、8章にチャットサーバあった.....
chatでテスト難しくね?それともワタシのアーキテクチャがダメなのか? ← このへん改善やな....

工夫したとこ

  • ターミナルからSSHでつなぐので、ルームでトークを分ける機能とかいらね!ってことでルームは公開ルーム1つだけっす!
  • 過去のトークはgrep検索したいやん!ってことでテキストファイルでトークを残すことにしました!

https://github.com/kuritayu/infra-tools/blob/master/cmd/tchat/main.go
go get github.com/kuritayu/infra-toolsでも取れます

とりあえず使い方。

  1. 作業サーバにSSHでログイン
  2. tchat &でサーバを起動(-pでポートを指定できる)
  3. 別ターミナルからSSHでログイン
  4. tchat -cでサーバに接続
  5. 名前を聞かれるので適当に入れる
  6. メッセージ入れると接続している人全員に配信する
NAME:
   tchat - chat tool by terminal

USAGE:
   tchat [global options] command [command options] [arguments...]

VERSION:
   1.0

COMMANDS:
   help, h  Shows a list of commands or help for one command

GLOBAL OPTIONS:
   -c             (default: false)
   -p value       (default: 7777)
   --help, -h     show help (default: false)
   --version, -v  print the version (default: false)
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む