JVM周辺ツールについてまとめる
はじめに
JVMの周辺ツールをたまに使用するが、使うタイミングで毎回調べているので、一度しっかりとまとめようと思う。
実行結果はJava8のものになります。
jcmd
https://docs.oracle.com/javase/jp/8/docs/technotes/tools/windows/jcmd.html#CIHEEDIB
JDKをインストールした時に付属している。
JMVに対して診断コマンドを送ることができる。
フライトレコーダーの制御や、GCを強制的に起動させるいった操作が可能。
Java9ではコマンドが増えている。
主に使っている機能は下記
- JFRの制御
- スレッドダンプ
# プロセス番号の確認 $ jcmd 5361 sun.tools.jcmd.JCmd 5146 info.repli.sample.mbeans.Hello # 送信できる診断コマンドの一覧 $ jcmd 5164 help 5146: The following commands are available: JFR.stop JFR.start JFR.dump JFR.check VM.native_memory VM.check_commercial_features VM.unlock_commercial_features ManagementAgent.stop ManagementAgent.start_local ManagementAgent.start GC.rotate_log Thread.print GC.class_stats GC.class_histogram GC.heap_dump GC.run_finalization GC.run VM.uptime VM.flags VM.system_properties VM.command_line VM.version help For more information about a specific command use 'help <command>'. # JFRの起動 ## 商用機能のアンロック jcmd 5146 VM.unlock_commercial_features ##起動 jcmd 5146 JFR.start filename=/tmp/`hostname`-`date -u +"%Y-%m-%d"`.jfr duration=180s settings=$JAVA_HOME/jre/lib/jfr/default.jfc # スレッドダンプ jcmd 5146 Thread.print # GC実行 jcmd 5146 GC.run # System.gc() jcmd 5146 GC.run_finallization # System.runFinalization()
jconsole
JVMの情報や、提供されているMBean情報の取得、操作ができるGUIツール。
JDKをインストールすると付属している。
https://docs.oracle.com/javase/jp/7/technotes/guides/management/jconsole.html
# 起動 $ jconsole
リモートのプロセスに接続することも可能。
jmxterm
MBean情報の取得、操作がコマンドラインでできるツール。
JDKとは別にインストールする必要あり。
後述するSJKのmxコマンドでも同じことはできる。
ダウンロード
http://wiki.cyclopsgroup.org/jmxterm/download.html
使い方
ダウンロードした jmxterm-1.0.0-uber.jar をJMXコンソールにアクセスしたいサーバに持っていく。
インタラクティブに使用
# java -jar jmxterm-1.0.0-uber.jar -u <USER> -p <PASS> -l <hostname> Welcome to JMX terminal. Type "help" for available commands. $> beans #MBeanの一覧が出力される ... $> get <取得したいMBeanのAttributeを指定>
JFRとJMC
JFR : https://docs.oracle.com/javacomponents/jp/jmc-5-4/jfr-runtime-guide/about.htm
JMC : https://docs.oracle.com/javacomponents/jp/jmc-5-5/jmc-user-guide/jmc.htm
※ JFR(Java Flight Recoder)とJMCは共に本番環境で使用するには商用ライセンスが必要になる。
そういえば、去年、JFRがOpenJDKに寄贈されるってブログにかかれて少し話題になっていたけど、その進捗どんな感じなんだろう。
https://blogs.oracle.com/java-platform-group/faster-and-easier-use-and-redistribution-of-java-se
jcmd等からJFRを起動し、出力されたファイルをJMCで読むことで、JFRを実行していた間のJVMの様々な情報が確認できる。
ちなみにJava9からはJMCのUIが大幅に変わっています。
SJK(Swiss Java Knife)
https://github.com/aragozin/jvm-tools
JVMのトラブルシューティングに便利なツール群
付属しているコマンドは下記
- ttop : topコマンドのJVMのようなもの、スレッド単位でのCPU使用率を表示する
- jps : JVMのプロセス表示、jcmdを引数なしで実行した場合と同じだが、フィルタや表示のカスタマイズができる
- hh : ヒープヒストグラム表示、jcmdのGC.class_histogramの高機能版、オプション次第ではフルGCが発生する
- gc : GCの実行状態を監視して表示
- mx : MBean情報の取得と操作、jconsoleやjmxtermと同じことができる
- stcap : スレッドダンプと一定期間取得
- ssa : stcapで取得したスレッドダンプを解析
- stcpy : スレッドダンプファイルをまとめたり、フィルタしたりといった操作を実施
おわりに
基本的にはjcmdとSJKを抑えておけば問題ないと思います。
自分はSJKの存在を知る前にjconsoleとjmxtermを使っていたのでMBean系の操作はこの2つを使用し続けてます。
VimConf2017 行ってきた
Vimmerのお祭りである、VimConfに行ってきました。
http://vimconf.vim-jp.org/2017/
会場は秋葉原駅から徒歩2分のアキバホールで、席には電源完備されていて心置きなくvimができる環境。 スライド、動画が後日公開されるらしい。
感想
- 便利そうな設定やプラグインについて知れてよかった
- 以外とwindowユーザ多い
- 会場がすごい人だらけですごかった
- どのセッションもすばらしくて非常に濃いカンファレンスでした
各セッションの感想とメモは下記。
Vim, Me and Community
https://docs.google.com/presentation/d/14pViuMI_X_PiNwQD8nuGRG72GUqSeKDqoJqjAZWS39U/edit
vimを使い初めてからの話が主で、最後にすこしvimのコミュニティについての話 。
プラグイン開発をどうやって初めて行ったか、何に気をつけて作っているかは興味深い話だった。
The Past and Future of Vim-go
https://speakerdeck.com/farslan/the-past-and-future-of-vim-go
vim-goの作者
vim本体でのgoのサポートが終わったので、vim-goを作った
なんでvim-goが有名になったか
- 小さいpluginがありすぎていた
- 他のpluginにロードマップがなかった
- ドキュメントがない問題を解決した
- この作業は面白くない
- markdownサポートのPRをまっている
- UXを向上していった
どうして必要なのかを説明してとても勉強になった。
Creating your lovely color scheme
カラースキームの話
Icebergの作者
人生の33%はcolor schemeらしい
- 最初にコンセプトを決めると、後々役に立つ時がある
- 代表的な色を決める
- preferred groupってやつがあってこれに設定すると他のにも引き継がれる
- HSB/HSLを使うのがおすすめ
- カラーパレットを作る時は基準を決めて色相だけを変える
- lovelyにする
- 先人をどこから探すか
- colorswat.ch : スター数が多い、プレビューがしっかりしているスキーマを表示するwebサービス
http://colorswat.ch/vim
- colorswat.ch : スター数が多い、プレビューがしっかりしているスキーマを表示するwebサービス
color schemeを作る時以外にもプレゼンのデザイン考える時とか参考になりそうな内容だった。
vim-mode-plus: The most ambitious vim emulator in the world
https://qiita.com/t9md/items/236d09fea9bcdfabdcea
atomでvim-modeを作るプラグインの話。
単純にvim-modeがあるだけじゃなくて、便利な機能が追加されていて、それの紹介もあった。
特にmove-{up|down}-to-edgeが便利そうだった。
Vim and Compatibility
http://lamsh.github.io/slide/2017/20171104_VimConf2017/index.html
POSIX原理主義といろんな環境で動くvimrcを書く方法についての話。
OSと文字コードの対応が特に大変そうな感じで、実際には自分が触る環境は多くても3種類ぐらいなのでその中で動けばいいかなーって感想。
neosnippet.vim + deoppet.nvim
https://www.slideshare.net/Shougo/neosnippetvim-deoppetnvim-in-vim-conf-2017
暗黒美夢王さん!
「テキストエディタは世界のすべて」
- neosnippet.vim
- marker type snippet plugin
- 日本では有名
- snipMate syntax
- snopMate.vim
- 有名
- 最近は開発が活発ではない
- マーカータイプではない
- UltiSnips
- snipMateとは互換性がない
- 外国ではおそらく一番有名
- 多機能
- マーカータイプではない
- neovimでは遅い
- カーソルの移動先にマーカーを作って、そこに移動する
- 実装が楽
マーカーがないやつの特徴は
- 実装が大変
- パフォーマンスもよくはない
- つねにバッファを監視してうごく
- カーソルを戻す実装がしやすい
開発中のスニペットプラグイン 「Deoppet.nvim」 https://github.com/Shougo/deoppet.nvim
- neosnippet互換のsyntax
- マーカーがないタイプのスニペットプラグイン
- extended Marks というneovimの新機能を使う予定(現在PRにある機能 )
- 試すためにはneovimの特定のブランチを自分でビルドして黒魔術する必要がある
How ordinary Vim user contributed to Vim
https://speakerdeck.com/daisuzu/how-ordinary-vim-user-contributed-to-vim
vim本体にpatchを送る話。
「必要なものはコントリビューターになりたいという強いパッション」
送ったパッチの話
- 辞書ファイルにパスを指定できなくなった問題を直した
- ある朝vimをビルドするとエラーが
- ちょうどvimconf2016のあとでpatch熱があった
- パッチとテストを書いた、コミュニティの状態を調べた結果、送ったのはテストだけ
- シソーラス補完のファイルのパスのチェックがなかった
- 辞書ファイルのチェックをシソーラス補完にも追加した
- インサートモードの補完がなかなかでない問題があった
- 補完候補を表示するなかで不要な処理をしていた
- 自分以外にも気づいた同僚がいたので、コントリビューターに仕立て上げようとした
- 転職することになったので、同僚に任せずにパッチを書いた
patchを送る先
この発表が一番記憶に残っている。
淡々と話していましたが、実際はすごいことを成し遂げていてとても素晴らしいと思いました。
The new syntax highlighter for Vim
https://speakerdeck.com/pocke/the-new-syntax-highlighter-for-vim
syntax highlighterの話。
iro.vim : 新しいsyntax-highlighterを作った、まだサポート言語は少ないがrubyはだいたいいける
言語自体のパーサーを使用して、間違ったハイライトをしない用に作っている(ASTベースでのsyntax-highlighter)。
パフォーマンスの問題はある、rubyなら10000行を超えると落ちる -> しかしパースの問題ではなくて、vimでmatchadpos()を大量にしようすると遅くなるらしい。
You've been Super Viman. After this talk, you could say you are Super Viman 2 -- Life with gina.vim
gina.vimの紹介
- git用のプラグイン
- 簡単なコマンド
- TAB補完できる
- . で繰り返しできる
めっちゃ便利そう
pythonでのdebug(pdb,pudb)のメモ
Pythonのdebugで使用するpdbとpudbについてのメモ
pdb
対話形式のデバッガ、標準ライブラなのでインストールなしで使える
https://docs.python.jp/3/library/pdb.html
主なコマンドは下記
コマンド | 効果 |
---|---|
b | ブレークポイントを設定 |
c | ブレークポイントまで移動 |
n | 現在の行を実行し、次の行で停止。次の行が関数だった場合は関数の中では止まらない |
s | 現在の行を実行し、次の行で停止。次の行が関数だった場合は関数の中で停止 |
p | 変数の値を表示 |
pp | pretty-printで変数を表示 |
q | デバッガ停止 |
r | 関数を抜ける |
list | 実行中の行の周辺を表示 |
whatis | 式の型を表示 |
# python -m pdb スクリプト名 $ python -m pdb sample.py (Pdb) b 19 # <- 19行目にブレークポイントを設置 (Pdb) n # <- 1行実行 -> from __future__ import print_function (Pdb) list # <- 現在の行の周辺を表示 1 # vim: fileencoding=utf-8 2 3 from __future__ import division 4 -> from __future__ import print_function 5 from __future__ import unicode_literals 6 from __future__ import absolute_import 7 try: 8 from future_builtins import ascii, filter, hex, map, oct, zip 9 except ModuleNotFoundError: 10 pass # running python version is 3 11 (Pdb) c # <- ブレークポイントまで移動 -> x = div(x, i) (Pdb) list 14 return x / y 15 16 def main(): 17 x = 6 18 for i in [3, 2, 1]: 19 B-> x = div(x, i) 20 return x 21 22 if __name__ == '__main__': 23 main() [EOF] (Pdb) c -> x = div(x, i) (Pdb) list 14 return x / y 15 16 def main(): 17 x = 6 18 for i in [3, 2, 1]: 19 B-> x = div(x, i) 20 return x 21 22 if __name__ == '__main__': 23 main() [EOF] (Pdb) p i # <- iの値を表示、ループの2回目なので、i は現在2 2 (Pdb)
起動時に指定する以外にも、import pdb; pdb.sey_trace()
を記述することで、コード中で起動することもできる。
# vim: fileencoding=utf-8 from __future__ import print_function def main(): print('hoge') import pdb; pdb.set_trace() # ここでpdbを起動する print('fuga') if __name__ == '__main__': main()
pudb
pdbよりも高機能なデバッガ、こちらはインストールが必要
$ pip install pudb
基本的な操作はpdbと同じ。
困った時は?
でヘルプがでるのでそれを見ればいい。
<C-x>
でpythonを実行できるペインに移動でき、ここでreplのようにいろいろ試せるのが便利。
起動は下記
$ pudb3 sample.py
pyconjp 2017に参加して来ました
概要
9月7,8,9,10で開催されたpyconjp 2017に参加してきました。
カンファレンスは8,9でしたが、7にチュートリアル、10に開発スプリントが開催されています。
また、今年はCfPをだしたが採択されなかったトークを喋るRejectConも開催されたようです。
今年のテーマは「OUTPUT & FOLLOW」
公式サイト : https://pycon.jp/2017/ja/
セッション感想
セッションのスライドはだいたい公開されており、toggterにもまとまっていたので詳しくはそちら
セッションのメモは以下
野球を科学する技術〜Pythonを用いた統計ライブラリ作成と分析基盤構築
- 野球ユニフォームで登壇が正装
- 分析基盤を構築した話をする
- 気軽に作って壊せる
- 使いたい・試したいライブラリを積極活用
- OSSにする
- DBはMySQL
- データはスクレイピング(Scrapy)、時系列データとして使いたいのでAirflow
- 実験はjupyter
- scrapyはクローラー界のRoRと読んでいいぐらい高機能
- airflow
- ジョブ管理
- 結構高機能
- 意外と苦労した
- 分析
- 定期的に見るか、分析に使うかで使い分ける
- 定期的はRedash
- 実験とかはjupyter
Pythonで大量データ処理!PySparkを用いたデータ分析のきほん
- データ量がスケールしても動く
- 大規模データに対する機械学習
上記のような時にSpark - RDDはJVMで実行しないから遅い
- PySparkでpandasとDataFrameで変換すると遅い
- 100kのデータの変換に7分かかる
- apache Arrow https://japan.zdnet.com/article/35078163/
Kivyによるアプリケーション開発のすすめ
https://www.slideshare.net/JunOkazaki1/pyconjp2017-kivy
- python3.5
- mac,Linuxでも動くはず
- MITライセンス、Qtとは違う!
- UIはkvという独自言語
- kvはCSSのBootstrapのようなもの
- kvを使用するのが普通、その方がコードが簡潔
- kivyを今使うのは結構たいへんそう
- デモは良さげ
len()関数がオブジェクトの長さを手にいれる仕組み
https://www.slideshare.net/shimizukawa/how-does-python-get-the-length-with-the-len-function
- len()が戻り値の型をintで保証
- Adapter Patternで実装されている
- スライドがすごく分かりやすかった
- 公式ドキュメントの「デザインと歴史」を読めばいろいろわかりそう https://docs.python.org/ja/3/faq/design.html
Pythonistaで始めるiOSプロトタイプ開発
Pythonと機械学習によるWebセキュリティの自動化
https://www.mbsd.jp/insight.html https://t.co/thfG8n2080
- Webアプリケーション診断を自動化
- 従来
- アプリをクローリングして疑似攻撃
- 判定
- 少ない手数で脆弱性を検出する(いろいろするわけではない)
- HTML,JSの理解 - LSTM
- 防除機構の回避 - 多層パーセプトロン、Q学習、GA
- LSTM
- 時系列データを対象としたアルゴリズム
- 高度すぎてついていけなかった
2日目keynote
https://speakerdeck.com/sinhrks/pandasdefalseosshuo-dong-shi-li-tozui-chu-false-bu
- pythonと科学計算
- pandasのOSS活動
- pandas : データ分液のためのデータ構造を提供するパッケージ
- 現実の汚いデータ(フォーマットがバラバラ)を効率的に扱えるのが便利
- データの理解、データ準備に使用される
- pandas : データ分液のためのデータ構造を提供するパッケージ
- OSS活動 最初の一歩
- コミッタの役割の話は興味深い
- インフラの整備とかもやってる
- プロダクトとコミュニティの品質の維持をやるのが大事
- プロダクト品質の維持
- コミッタの役割の話は興味深い
Pythonで実現する4コマ漫画の分析・評論 2017
https://slideship.com/users/@esuji/presentations/2017/08/FSKS46VL9ivVSpUE4Gaamh/
- 情熱駆動開発!!
- OCRは三国志の人と同じGoogle OCR
- 誰が何処に出ているか等も分析したい
- dlibの物体検出器で人物判定
- 横向き、後ろ向き、顔の重なりがあるのでそれを調査
- 期待した精度はでなかった
- 検出人物の分類
- CNNを利用
- だめだった
The theory of Serverless development by Python (理論から学ぶPythonによるサーバレス開発)
https://slideship.com/users/@marcy-terui/presentations/2017/09/9PzXZzcJfBR1ENEMmMbGSf/ https://www.slideshare.net/acloudguru/ant-stanley-being-serverless
- Serverlessとは
- 管理すべきサーバがない
- サーバOSがない
- 常駐サーバプロセスがない
- Function as a Service
- 関数単位で独立した環境とリソースを提供
- 関数単位で横にスケール
- 高い抽象度
- Function SaaS
- Serverlessがどうして登場したのか
- システム開発は他者への依存を高める方向へ向かっている
- どのように実装するか
- Serverlessに向いているもの
- DBAとのコネクションコストを考える
Clearer Code at Scale: Static Types at Zulip and Dropbox
英語セッションだったので聞くのに必死でメモはなし
英語スライドに機械翻訳ぽい日本語があった
- mypyの話
https://github.com/zulip/zulip/blob/master/docs/mypy.md
http://qiita.com/t2y/items/2a1310608da7b5c4860b
Pythonをとりまく並行/非同期の話
https://tell-k.github.io/pyconjp2017/#1
- python3.6リリースパーティーで聞いた話と大体同じ
- asyncio のイベントループポリシーを差し替えることができるのは知らなかった
SREエンジニアがJupyter+BigQueryでデータ分析基盤をDev&Opsする話
https://speakerdeck.com/yuzutas0/20170909
カンファレンス感想
Neovimでgolangを書く設定 備忘録
概要
Macにgolangをインストールし、Neovimで書く環境を整えます。
インストール
まずはgolangをインストールします。
$ brew install go $ nvim .zshrc #下記を追加 if [[ -d /usr/local/opt/go ]];then export GOPATH=$HOME/work.go export PATH=$PATH:$GOPATH/bin:/usr/local/opt/go/libexec/bin fi
設定
設定するものは下記です。
GOPATH
golangで使用するディレクトリをGOPATHに指定する必要があるので、設定します。
GOPATH : https://github.com/golang/go/wiki/GOPATH
.zshrcに下記を追加します。
今回は~/devをGOPATHに指定しています。
#go if [[ -d /usr/local/opt/go ]];then export GOPATH=$HOME/dev export PATH=$PATH:$GOPATH/bin:/usr/local/opt/go/libexec/bin fi
GOPATHを指定すると、今後はgo getでインストールするgolangのライブラリがこの下にインストールされるようになります。
補完
deoplete.nvimを使っているので、deoplete-goをセットアップすればいいです。
設定も公式サイトのものをとりあえずそのまま使用しています。
deoplete-go : https://github.com/zchee/deoplete-go
依存しているものをインストールします。
$pip2 install --upgrade neovim $pip3 install --upgrade neovim $go get -u github.com/nsf/gocode #GOPATHで指定したディレクトリの下にインストールされる
dein_lazy.tomlに下記を追加します。
[[plugins]] repo = 'zchee/deoplete-go' on_ft = 'go'
vim-go
ちょっと前だとvim-goはneovimに対応してなかったようですが、今は使えるようになっているみたいなのでvim-goを入れます。
dein_lazy.tomlに下記を追加します。
[[plugins]] repo = 'fatih/vim-go' on_ft = 'go'
インストールしたら下記をneovimで実行すると、vim-goで使うライブラリがGOPATHの下にインストールされます。
:GoInstallBinaries
vim-go自体にチュートリアルがあるのでそれをやれば一通りの使い方はわかりそう
vim-go-tutorial : https://github.com/fatih/vim-go-tutorial
シンタックスチェック
neovimではSyntasticの代わりにneomakeでシンタックスチェックをするので、neomakeをインストールします。
dein.tomlに下記を追加します。
[[plugins]] repo = 'neomake/neomake'
a tour of go をやりながら書いていたメモのまとめ
エントリーポイント
- エントリポイントはmainパッケージのmain関数
package main func main() { // write your some code }
関数
- 複数の値を返せる
- 戻り値に名前をつけることができる
// func 関数名 (引数,...) 戻り値の型 { } func add1(x int, y int) int { //引数がx,yでともにint型 //戻り値の型はint return x + y } func add2(x, y int) int { //add1と同じだが、引き数の型をまとめて宣言 return x + y } func swap(x, y string)(string, string) { //引数がx,yで共にstring型 //戻り値が2つあり、共にstring型 return y, x } //naked returnと呼ばれる方法で関数が短い場合にのみ使うべき func split(sum int)(x, y int) { //戻り値の指定部でx,yの変数を宣言している x = sum * 4 / 9 y = sum - x //関数の宣言で指定した値を自動的に返す return }
defer
- 呼び出し元が終わるタイミングで実行される
- 複数のdeferを書いた場合は後に書いてあるものが先に実行される(LIFO)
- 引数の評価は実行時ではなく、deferが書いてある場所で行われる
- 絶対開放しないと行けないリソースなどの処理に便利(ファイルのクローズ、ミューテックス(排他制御)のアンロック)
import ( "fmt" ) //これを実行すると3,2,1の順番で表示される func main(){ i := 1 defer fmt.Println(i) i = 2 defer fmt.Println(i) i = 3 defer fmt.Println(i) }
定数
const
で定義- 定数は変数に代入する時や、式の中で型がきまる(宣言時は型が決まっていない)
const u = 1 const p = 2.0
変数宣言
var
で宣言- 変数のスコープは
for
,if
,func
,global
がある - 関数の中での宣言には
:=
も使える、var
を省略し、宣言と同時に初期化をする
var c,python,java bool //3つともbool型 var i, j int = 1,2 //2つともint型でi=1,j=2で初期化 var c,python,java = true,false,"no" //初期化時に型が決まるので、明示的に型を書かないでも大丈夫 func main() { k := 3 //関数の中なのでvarを省略する方法が使える }
型
基本型
型 | 初期値 | 備考 |
---|---|---|
bool | false | 論理値 |
string | “” | 文字列 |
int, int8, int16, int32, int64 | 0 | 整数、特別な用途以外ではintを使用 |
uint, uint8, uint16, uint32, uint64, uintptr | 0 | 符号なし整数、unitptrはポインタの値を表現するようの整数型 |
byte | 0 | バイト単位でデータを扱う、alias for uint8 |
rune | 文字単位のデータを扱う、alias for int32 | |
float32, float64 | 0 | |
complex64 , complex128 | 複素数 |
型変換
- 暗黙の型変換はない
- 変換後の型をTとした時、
T(v)
でvをT型に変換する
func main() { var x int = 3, 4 var z uint = uint(x) var f float64 = float64(x) }
ポインタ
*変数名
で宣言した場合はポインタ- ポインタの初期値は
nil
&
オペレータはポインタを返す)*
オペレータはポインタが指す先を返す(dereferencingまたはindirecting)
import( "fmt" ) func main(){ var *p int //int型ポインタ i := 1 q := &i //qもint型ポインタになる fmt.Println(*q) //1が表示される }
構造体
type 構造体名 struct { 変数1 変数2 変数n } var v 構造体名{初期値} v.変数1 = 10
- goにはクラスはない
- 構造体はフィールドの集まり
- 構造体のフィールド名は大文字で始めるのが多い
import( "fmt" ) type Vertex struct { X int Y int } func main() { v1 := Vertex{1, 2} v2 := Vertex{x: 1} //yは初期値になるので0 v3 := Vertex{} //x,y共に初期値は0 p := &Vertex{1, 2} //構造体のポインタもある q := &v1 //構造体のポインタになる q.x = 1e9 //本来なら (*q).vで参照するが、syntax sugerがある fmt.Println(q) }
array
//宣言 var 変数名 [要素数]型 var 変数名 [要素数]型{初期値,...} //代入、参照 変数名[要素] = 値 fmt.Print(変数名[要素])
- 配列の長さは変更不可
import ( "fmt" ) func main() { var a [2]string a[0] = "Hello" fmt.Println(a[0]) fmt.Println(a) primes := [6]int{2, 3, 5, 7, 11, 13} }
slice
var 変数名 []型
- 可変長
- リストのようなもの
- sliceは配列への参照をもっているようなもの
- sliceは参照渡し
- sliceには下記がある
- 長さ(length) : 含まれる要素の数
- 容量(capacity) : sliceのサイズ
- ゼロ値は
nil
、長さと容量は0となる - 組み込み関数
make
を使用して作成できる - sliceの入れ子もできる
- sliceへの要素の追加は
append
、追加時にsliceの容量が足りない場合は自動的に良い大きいサイズのsliceが作られ、それを返す - forループ時はrangeを利用
import ( "fmt" ) func main(){ primes := [6]int{2, 3, 5, 7, 11, 13} var s1 [] int = primes[1:4] //sはint側のスライスで3,5,7が入ってる var s2 []bool{true, true, false} //最初からスライスを作ることもできる len(s1) //要素数は3 cap(s1) //サイズも3 //下記はすべて同じ意味になる、下限は0、上限は配列のサイズがデフォルト値になるため var s3 []int = primes[0:6] var s4 []int = primes[:6] var s5 []int = primes[0:] var s6 []int = primes[:] //nil slice var s7[]int //s7 == nil がtrueになる a := make([]int, 5) //sliceのcapが5でlenも5、各要素は0で初期化されている b := make([]int, 0, 5) //sliceのcapが5でlenは0のsliceを返す //要素の追加 c := append(a, 1,2,3,4,5,6) //aの容量は5ですでにlenも5なので大きいサイズのsliceが作られる //戻り値は新しいsliceで元のslice自体は変化していないので注意 //上記の場合はcは大きいサイズのsliceでaはappend前と変化なし //入れ子のslice board := [][]string{ []string{"_", "_", "_"}, []string{"_", "_", "_"}, []string{"_", "_", "_"}, } fmt.Println(board[0][0]) //forループ for i, v := range s2 { // i は index, v はvalue, pythonのenumerate関数と同じような動き fmt.Println(i) fmt.Println(v) } for i := range s2 { //indexだけ使う場合 fmt.Println(i) } for _, v := range s2 { //valueだけ使う場合 fmt.Println(i) } }
map
var 変数名 map[キーの型]値の型
- キーと値を関連づける
- mapのゼロ値はnil,nilはキーを持っておらず、キーを追加することもできない
make
関数を使用して初期化する- 新しいキーは代入するだけで作れる
- 値を指定して初期化もできる
- キーの削除は
delete
関数 - キーの存在確認は参照時の戻り値で判定する
import ( "fmt" ) //緯度経度を持つ構造体 type Vertex struct { Lat, Lon float64 } func main() { var m map[string]int //キーがstring,値がint,この時は型が決まっているが値はnil m = make(map[string]int) //map型のインスタンスを作ったような状態 //m := make(map[string]int) //上の2行をまとめてこれでもOK m["age"] = 26 //代入 fmt.Println(m["age"]) //参照 //宣言と初期化と同時に var n map[string]Vertex { "Bell Labs" : Vertex{ 40.68433, -74.39967, }, "Google" : Vertex{ 37.42202, -122.08408, }, } //値の型が単純な型名の場合は値の型から推測できるので、省略可能 var o map[string]Vertex { "Bell Labs" : { 40.68433, -74.39967, }, "Google" : { 37.42202, -122.08408, }, } //要素の削除 delete(n, "Bell Labs") //Bell Labsを削除 //キーの存在確認 elem, ok := n["Bell Labs"] //Bell Labsは削除済みなのでokはfalse, elemは要素の型のゼロ値なので今回はnil elem, ok = n["Google"] //Googleはまだあるのでokはtrue,elemは要素の値を返す }
関数型(function values)
- 関数も変数として扱える
- 他の関数に関数を渡すことができる
- 関数の戻り値として関数を返すこともできる
import ( "fmt" "math" ) //compute関数は引数としてfloat64型の値を2つとり,float64型を返す関数をとり、float64型を返す func compute(fn func(float64, float64) float64) float64 { //引数として受け取ったfloat64型の値を2つとり,float64型を返す関数に引数3と4を指定して呼び出す return fn(3, 4) } func main() { //hypotは関数型 hypot := func(x, y float64) float64 { return math.Sqrt(x*x + y*y) } //hypotに格納されている関数を呼び出す fmt.Println(hypot(5, 12)) //compute関数にhypot関数を引数として渡す fmt.Println(compute(hypot)) //compute関数にmath.Pow関数を引数として渡す fmt.Println(compute(math.Pow)) }
closure
- 関数の外の値を関数に対して紐付ける(bind)する仕組み
- closure関数を返す関数を作成し、closure関数を返す前にclosure関数に紐付ける変数を宣言する
import "fmt" //adderはint型と引数としてとり、int型を返す関数を返す func adder() func(int) int { sum := 0 //adderで返す下記の関数からはsumを参照でき、adderを呼び出して新しい関数を返すたびにそれぞれの関数に別々のsumが紐づく return func(x int) int { //closure関数 sum += x return sum } } func main() { //posとnegにはそれぞれ別のsumが紐づく pos, neg := adder(), adder() for i := 0; i < 10; i++ { fmt.Println( pos(i), neg(-2*i), ) } }
if
if 条件式 { } else if 条件式 { } else { } if 式; 条件式 { }
- ()はいらない
- 条件の前に簡単な式を書くことができる
import ( "math" ) func main() { x := 1 if x < 0 { } else if x >= 5 { } else { } n := 2 lim := 10 if v := math.Pox(x, n); v < lim { //v := math.Pox(x, n);を実行したあとにv < limが評価される //vのスコープはこのifの中だけ } else { //vはelseでも使える }
ref : https://gobyexample.com/if-else
switch
- breakがなくても次のcaseは実行されない
- 他言語でbreakを書かなかった場合と同じ動作をさせたい場合は
fallthrough
を書く - case式に関数を指定できる
- switchに式を書かない場合は、case式を評価し、trueになったcaseを実行する
func main() { i := 10 switch i { case 0: case 1: fallthrough case 2: case f(): //f()を呼び出した結果の戻り値をiを評価する、f()の前のcaseで実行する箇所が決まった場合はf()も呼ばれない default : //今回はこれが実行される } now := 1 switch { //一番最初にcase式がtrueになったcaseが実行される case now < 12: //今回はこれが実行される case now < 18: default: } }
for
for 初期化部; 条件式; 増分 { } for 条件式 { //whileの代わり } for { //無限ループ }
- ()はいらない
- 条件の前に簡単な式を書くことができる
- whileはないので、whileの動作を実現したい時はforで初期化部と増分を書かない
- break,continueはある
- goにはpythonのrange的なのものはない
import ( "fmt" ) func main(){ for i := 0; i < 10; i++ { //iのスコープはforの中だけ } sum := 1 for sum < 100 { //whileの代わり sum += sum } x := 0 for { //無限ループ if x >= 3 { break } x++ } for i := 0; i < 10 ; i++ { if i % 2 == 0 { continue } fmt.Println("奇数:", i) }
メソッド
//func レシーバ- 関数名 戻り値の型 func (i Vertex) Abs() float64{}
- golangにはクラスはないが、型にメソッドを定義できる
- 特定の型にメソッドを追加する場合はレシーバーを使う
- レシーバーは同じパッケージにある型にだけ追加できる
- 組み込み型にレシーバを追加したい場合は
type
で型に別名をつける - ポインタに対してもレシーバを追加できる
- ポインタに対してレシーバを追加した場合は参照渡し、それ以外は値渡しになる
- ポインタレシーバ(ポインタに対してレシーバを追加したもの)と変数レシーバ(ポインタ以外にレシーバを追加したもの)を混在させるべきではない
- ポインタレシーバの場合はメソッド呼び出し毎に変数のコピーを作らないので、こちらを使うのがおすすめ
- 関数の場合は引数で渡すの値がポインタかそうでないかを意識しないと行けないが、レシーバの場合はgoが良しなに変換してくれる
import ( "fmt" "math" ) type Vertex struct { X, Y float64 } //型VertexにAbs()を紐付ける func (v Vertex) Abs() float64 { //vの値を参照できる return math.Sqrt(v.X * x.X + v.Y * v.Y) } //ポインタレシーバ func (v *Vertex) Scale(f float64) { v.X = v.X * f v.Y = v.Y * f } type MyFloat float64 //float64にMyFloatという別名をつけ、MyFloatに対してレシーバーをつける func (f MyFloat) Abs() float64 { if f < 0 { return float64(-f) } return float64(f) } func main(){ v := Vertex{3, 4} //Vertex型のvはAbs関数を呼び出せる fmt.Println(v.Abs()) v.Scale(5) fmt.Println(v) f := MyFloat(-math.Sqrt2) fmt.Println(f.Abs()) }
インターフェイス型
type 型名 interface { //実装すべき関数 //実装すべき関数 //実装すべき関数 }
- goのインターフェイスは型
- インターフェイス型にはその型が実装すべきメソッドが定義されている
- インターフェイス型に定義されているメソッドをすべて実装した時に自動的にそのインターフェイスを実装したことになる(明示的にどのインターフェイスを実装するのか書かないでいい)
- goではnilをレシーバとしてメソッドを呼び出されても、適切に処理するようにメソッドを記述する
import ( "fmt" ) type Abser interface{ Abs() float64 } type MyFloat float64 //Absを実装したのでMyFloatはAbser型にもなる func (f MyFloat) Abs() float64 { if f < 0 { return float64(-f) } return float64(f) } type Vertex struct { X, Y float64 } //Absを実装したのでVertexはAbser型にもなる func (v *Vertex) Abs() float64 { return math.Sqrt(v.X * v.X + v.Y * v.Y) } type I interface { M() } type T struct { S string } func (t *T) M() { //tがnilの場合でも適切に処理をする if t == nil { fmt.Println("<nil>") return } fmt.Println(t.S) } func main() { var a Abser f := MyFloat(-math.Sqrt2) v := Vertex{3, 4} a = f // a MyFloat implements Abser fmt.Println(a.Abs()) //MyFloatのAbs()が呼ばれる a = &v // a *Vertex implements Abser fmt.Println(a.Abs()) //VertexのAbs()が呼ばれる var i I var t *T //この時のTはまだnil i = t i.M() i = &T{"hello"} i.M() }
nil インターフェイス
import "fmt" type I interface { M() } func main() { var i I //ここのiの型はIインターフェイスだが、具体的な型(実装を持っている)が代入されていないので、ランタイムエラーになる i.M() }
emptyインターフェイス
- ゼロ個のメソッドを定義したインターフェイス
- 任意の型を代入できる
- 未知の型を扱うコードで使用する(fmt.Println()が代表例)
package main import "fmt" func main() { //iはemptyインターフェイス型なので任意の型を代入可能 var i interface{} describe(i) i = 42 describe(i) i = "hello" describe(i) } func describe(i interface{}) { fmt.Printf("(%v, %T)\n", i, i) }
type assertions
- インターフェイスにどの型が代入されているかを判定できる
import "fmt" func main() { var i interface{} = "hello" //この時iがstring型じゃなければここでpanicが引き起こされる s := i.(string) fmt.Println(s) //sにはiの値が入る,okにはtrue s, ok := i.(string) fmt.Println(s, ok) //fはfloat64のゼロ値になりokはfalse f, ok := i.(float64) fmt.Println(f, ok) f = i.(float64) // panic fmt.Println(f) }
type switch
- type assertionsを直列に使用する方法
import "fmt" func do(i interface{}) { //iの型で分岐するswitch文 switch v := i.(type) { case int: fmt.Printf("Twice %v is %v\n", v, v*2) case string: fmt.Printf("%q is %v bytes long\n", v, len(v)) default: //一致する型がcaseにない場合はdefaultが呼ばれる fmt.Printf("I don't know about type %T!\n", v) } } func main() { do(21) do("hello") do(true) }
よく使われるインターフェイス
- Stringer : stringとして表現できる型
type Stringer interface { String() string }
import "fmt" type Person struct { Name string Age int } //PersonはこれでStingerインターフェイスを実装した func (p Person) String() string { return fmt.Sprintf("%v (%v years)", p.Name, p.Age) } func main() { a := Person{"Arthur Dent", 42} z := Person{"Zaphod Beeblebrox", 9001} fmt.Println(a, z) //ここでPersonのString()が呼ばれる }
- Errors : エラーの状態を表現する
- goでは関数がよくerror型の値を返す、この値がnilの場合は処理が成功したことを示す
type error interface { Error() string }
import ( "fmt" "time" ) type MyError struct { When time.Time What string } //errorインターフェイスを実装 func (e *MyError) Error() string { return fmt.Sprintf("at %v, %s", e.When, e.What) } //errorインターフェイスを返す func run() error { return &MyError{ time.Now(), "it didn't work", } } func main() { if err := run(); err != nil { fmt.Println(err) } }
- Readers : データストリームを読む
//byte型を引数にとり、int型とerrorインターフェイス型を返す //bにデータをいれ、入れた数をnとして返す func (T) Read(b []byte) (n int, err error)
import ( "fmt" "io" "strings" ) func main() { r := strings.NewReader("Hello, Reader!") b := make([]byte, 8) for { //rの値をbに入れる //入った値がnに、失敗した場合はerrがnil以外になる n, err := r.Read(b) fmt.Printf("n = %v err = %v b = %v\n", n, err, b) fmt.Printf("b[:n] = %q\n", b[:n]) if err == io.EOF { break } } }
- Images : 画像を表現する
package image type Image interface { ColorModel() color.Model Bounds() Rectangle At(x, y int) color.Color }
import ( "fmt" "image" ) func main() { //imageインターフェイスが実装されているクラスを使ってみる m := image.NewRGBA(image.Rect(0, 0, 100, 100)) fmt.Println(m.Bounds()) fmt.Println(m.At(0, 0).RGBA()) }
goroutine
go 関数名() 変数名 := make(chan 型) //指定した型のchannelを作成 channel変数 <- 値 //値をchannel変数に書き込み 変数 := <- channele変数 // channel変数の値を読み込む
- メモリ空間は共有
- 通常の関数をgo 関数名で呼び出せばgoroutineとして呼び出せる
- goroutine間でデータを渡す時はchannelsを使用
- channelの読み書きの時にchannelのバッファに対して処理ができない場合は、他のgoroutineの処理を待つ
- channelにはバッファサイズを指定できる
- channelにこれ以上値を送信することがない時はchannelをcloseする
- channelに対してrange でループをしている時はchannelがcloseされるまでループする
- channelはgoroutine以外からもいじれる
- 使用できるchannelで分岐したい時はselectを使用する
- ブロックしないでchannelを使用したい時はdefault付きのselectを使用する
import ( "fmt" "time" ) func say(s string) { for i := 0; i < 5; i++ { time.Sleep(100 * time.Millisecond) fmt.Println(s) } } func sum(s []int, c chan int) { sum := 0 for _, v := range s { sum += v } c <- sum // send sum to c } func fibonacci(n int, c chan int) { x, y := 0, 1 for i := 0; i < n; i++ { c <- x //書き込みの毎に読み込みがあるまでここでロックされる x, y = y, x+y } close(c) //cに対してもう書き込まないのでそれを明示する } func fibonacci2(c, quit chan int) { x, y := 0, 1 for { select { //cに書き込めるかquitが読み込めるようになるまでここでロック case c <- x: x, y = y, x+y case <-quit: fmt.Println("quit") return } } } func main() { go say("world") //sayをgoroutineとして起動 say("hello") s := []int{7, 2, 8, -9, 4, 0} c := make(chan int) //chanel作成 go sum(s[:len(s)/2], c) go sum(s[len(s)/2:], c) x, y := <-c, <-c // cに値が入るまでここでロックされる fmt.Println(x, y, x+y) ch := make(chan int, 2) //channelのバッファサイズを2で宣言 ch <- 1 ch <- 2 //バッファサイズが2なので、連続して書き込める fmt.Println(<-ch) fmt.Println(<-ch) cf := make(chan int, 10) go fibonacci(cap(cf), cf) for i := range cf { //cfがcloseされるまでは読み込みを繰り返す fmt.Println(i) } cf2 := make(chan int) quit := make(chan int) go func() { for i := 0; i < 10; i++ { fmt.Println(<-cf2) } quit <- 0 }() //宣言と同時に呼び出し fibonacci2(c, quit) tick := time.Tick(100 * time.Millisecond) boom := time.After(500 * time.Millisecond) for { select { case <-tick: fmt.Println("tick.") case <-boom: fmt.Println("BOOM!") return default: //tickとboomの両方が読み込めない場合はdefaultを実行 fmt.Println(" .") time.Sleep(50 * time.Millisecond) } } }
mutex
import ( "sync" ) 変数名 sync.Mutex 変数名.Lock() //LockとUnLockの間が排他制御になる 変数名.Unlock()
- goroutine間でコミュニケーションを取る必要がないが、データのロックが必要な時に使用
import ( "fmt" "sync" "time" ) // SafeCounter is safe to use concurrently. type SafeCounter struct { v map[string]int mux sync.Mutex } //SafeCounter型にメソッドをつける func (c *SafeCounter) Inc(key string) { c.mux.Lock() //LockとUnlockで挟んでいるここが排他制御 c.v[key]++ c.mux.Unlock() } // Value returns the current value of the counter for the given key. func (c *SafeCounter) Value(key string) int { c.mux.Lock() defer c.mux.Unlock() //deferでUnlockを実行することもできる return c.v[key] } func main() { c := SafeCounter{v: make(map[string]int)} for i := 0; i < 1000; i++ { go c.Inc("somekey") } time.Sleep(1 * time.Millisecond) fmt.Println(c.Value("somekey")) }
Pythonのパッケージ周りについて調べた時のメモ
用語
パッケージングツール
- destribute : python標準のパッケージ管理用モジュール、destributeよりも多機能なsetuptoolsが基本的には使われる
- setuptools : 2017年8月2日現在、すくなくともpython2系のパッケージング時のデファクトスタンダード。
- distutils : setuptoolsよりも機能が少ないので、setuptoolsを使っていればよい
インストールツール
- easy_install : setuptoolsに付属している、PyPIからパッケージをダウンロードしてインストールできるコマンド
- ez_setup.py : setuptoolsをインストールする際に利用されるスクリプト
- pip : easy_installよりも高機能なインストーラー、easy_installではパッケージのアンインストール等ができない
配布形式
- egg : setuptoolsで定義されたpython Packageの配布形式、中身はpythonのコードやメタ情報を所定のフォーマットでzip圧縮したもの
- wheels : eggの後続のフォーマット
配布物の作成
- bdist : setup.pyを使ってビルド済み配布物を作成するコマンド、bdist_rpmやbdist_wininst等を作成できる
- sdist : setup.pyを使ってソースコード配布物を作成するコマンド
その他
- setup.py : パッケージに必要な情報を記述する
- init.py : pythonがあるディレクトリの目印
- PyPI : the Python Package Index、Pythonのパッケージが登録されている場所
テンプレート
from setuptools import setup, find_packages setup( name = "HelloWorld", version = "0.0.1", packages = find_packages(), #find_packages()はsetup.pyがあるディレクトリから__init__.pyがあるディレクトリを探す author = "repli", author_email = "repli@example.com", description = "This is an Example Package", license = "MIT", keywords = "package example examples", # 検索用のワード url = "", # もしあれば、プロジェクトのホームページ install_requires = ['docutils>=0.3'], #python以外に含めるデータ package_data = { '': ['*.txt', '*.rst'], } )