golangでbyte配列から整数型への変換メモ

メモ

package main

import (
    "fmt"
    "golang.org/x/crypto/scrypt"
    "encoding/hex"
    "encoding/binary"
    "bytes"
)


func main() {

    b := []byte{0x00, 0x00, 0x00, 0xFF}
    fmt.Println(b)
    fmt.Println(hex.EncodeToString(b))

    var i int32
    buf := bytes.NewReader(b)
    err := binary.Read(buf, binary.LittleEndian, &i)
    if err != nil {
        fmt.Println("binary.Read failded:", err)
    }

    fmt.Println(i)
}

package.jsonのpeerDependenciesについての理解

依存の解決の違い(dependencies, devDependencies, peerDependencies)

親アプリで利用されるためのnpmモジュールを開発している時に、このモジュールをインストールするときはmoduleA:0.5.0と一緒にインストールする必要がある」 というケースを考える

 親アプリ
 |
 |- このモジュール
 |          |
 |          |- moduleA

1. このモジュールのpackage.jsonのdependenciesにmoduleA:0.5.0を書いた場合
親アプリにも自動的にmoduleA:0.5.0がインストールされるが、もし親アプリのpackage.jsonにmoduleA:1.5.0が設定されてた場合は上書きされて実行時エラーになる



2. このモジュールのpackage.jsonのdevDependenciesにmoduleA:0.5.0を書いた場合
親アプリでnpm installした時に、このモジュールのdevDependenciesは無視されるのでmoduleA:0.5.0はインストールされないため実行時エラーになる
対処: 親アプリ側でmoduleA:0.5.0をpackege.jsonに書く必要がある



3. (1.か2.に加えて) このモジュールのpackage.jsonのpeerDependenciesにmoduleA:0.5.0を書いた場合
npm-v3より前の場合は、親アプリのnode_modulesにmoduleA:0.5.0も一緒にインストールされる(WARNは出る)
npm-v3以降の場合は、 `このモジュール@1.0.0 requires a peer of moduleA@^0.5.0 but none was installed.` みたいなWARNが出るだけでmoduleA:0.5.0はインストールされない


それぞれの違い

2.のケースはそもそもとして、このモジュールの実行に必要なmoduleA:0.5.0をdevDependenciesに書くのは間違いである(開発用途に必要なモジュールではなく、実行に必要なモジュールのため)

1.のケースは親アプリ側がこのモジュールを利用するときにmoduleA:0.5.0が必須なことに気づけないため、なんらかの理由で親アプリのpackage.jsonにmoduleA:1.5.0を入れた場合に、このモジュールが動かなくなることを事前に気づくことができない

そのため、3.のpeerDependenciesをこのモジュールが使っていれば、警告として親アプリ側に通知することができるので、親アプリ側は明示的に(意図的に)moduleA:0.5.0を追加することができる。

はまったところ

この時注意が必要なのは、peerDependenciesはあくまで親アプリ側に警告を促すだけである。
親アプリは `このモジュールがmoduleA:0.5.0に依存しているからそれを利用しよう'と意図的に親アプリのpackage.jsonにmoduleA:0.5.0を追加することができるということが重要である。
もしも親アプリがmoduleA:1.5.0を利用したかったとしてもこのモジュールはmoduleA:0.5.0を使っているので、それぞれのモジュールの依存バージョンの互換性を解決してくれるものではない

どういうときに使うのか?

開発ではmoduleA:1.5.0を使っているが、このモジュールを利用するときは最低でもmoduleA:0.5.0を使ってほしいときとか?

結局、親アプリでmoduleA:1.5.0を参照して、このモジュールではmoduleA:0.5.0を参照するようにして依存性をよしなに解決して同時に使いたい

そのままではできないっぽい。
(なんかごにょごにょ工夫すればできるかもしれないけど)

疑問に対する推測

peerDependenciesって親アプリに設定するものじゃないのか?

親アプリのpeerDependenciesに指定することにより、このモジュールがどのバージョンのmoduleAに依存しているのかを指定する使い方なのもと思ったがどうやら違うっぽい

  • 親アプリにpeerDependenciesを設定してもこのモジュールのバージョン依存を解決してくれるわけではないっぽい(WARN出るし)
  • そもそも、peerDependenciesの書式的にどのモジュールがどのモジュールのどのバージョンに依存しているという書き方ができない
じゃぁ、devDependenciesとpeerDependenciesの両方に違うバージョンで書いてあるOSSモジュールをよく見るのはなんで?

これとか
リリースバージョンの依存はpeerDependenciesに書いて、開発中とか動作確認中のものはdevDependenciesに書いているのでは?

このモジュールのpeerDependenciesだけに書いた場合、このモジュールでnpm iinstallした場合はどうなるの?

peerDependenciesに書いただけでは、npm installしてもnode_modulesにインストールされない。
dependenciesかdevDependenciesと組み合わせて利用するみたい。








あんまり情報がなくて推測の部分が多い。
あんまりしっくり来てないけどこれ以上時間かけられないのでこんなもんの理解でとどめておく。




package.jsonのpeerDependenciesについて調べた
http://yukidarake.hateblo.jp/entry/2016/02/16/201614

Peer Dependencies
https://nodejs.org/en/blog/npm/peer-dependencies/

家のRaspberry Pi 2 Model BにSoftetherでVPNを構築

海外に来てから家のNASにアクセスしたりするためにVPN環境を構築した。
自宅には家族しかいないので、万が一ネットワーク設定ミスったりしたらサーバーにアクセスできなくなってしまうので慎重に作業した

いくつか日本語の記事を読んだが、最終的にサーバー設定はWindows用のGUIアプリを使ってたのでコマンドで設定できる方法を模索した。
後から見てみたら、Mac用のGUIアプリも公式に用意されていたのでそっちを使う方法でもよかったのかもしれない

以下を参考にしたらサクッと構築できた。すごい

Goにおけるreflectまわり調べた

javaScalaとGoでそれぞれclass、型、インターフェース、メソッドの用語の意味が微妙に違うから混乱する
なんなら型クラスとかある

なぜ遅いか

  • 静的な型付けがされていたり、コンパイルされていたりする言語でもリフレクションアクセスの場合は interpretiveに解釈されるから 遅い
  • reflectionは メモリアロケーションが多く発生するため 遅い 恐らく、静的型且つ、コンパイル型であるGoにとってダイナミックにメモリアロケーションをするのは特にコストが高いのかも)

  • makeFunc()を見てみると、makeFunc.go#62で呼び出しているfuncLayout()の処理が重そう(完全に雰囲気だけど)
    funcLayout()は渡された汎用型(rtype)を「関数型だったら」「インターフェイス型だったら」とかいっこずつ分解していっって、値型によっても一つ一つみてレイアウト情報を取得してるっぽい。
    if runtime.GOARCH == "amd64p32" { みたいなコードもあるのでCPUアーキテクチャによる分岐もはいってる雰囲気
    いかにも重そう(な雰囲気)

  • 型情報を取得するときは、ValueOf()でValue型に変換して、Type()を呼び出す
    unsafe.Pointerを使って、型の種類ごとに処理が書いてある(Funcならこれやる、Interfaceならこれやるみたいな)
    type.uncommon()でFuncなのかArrayなのか、Sliceなのか…を分岐で判断してる
    それに応じてruntime/type.goのresolveTypeOff()でごにょごにょしてるが、reflectOffsLock()という関数を呼び出しているので、もしかしたらプロセスのメモリ空間のテキストセグメントにアクセスするときに、goroutine同士のメモリ競合しないようにロックを取得しているのかな?

参考

なぜリフレクションは遅いのか
http://postd.cc/why-is-reflection-slow/
golangのある生活
http://ameblo.jp/principia-ca/entry-11929774278.html
The Laws of Reflection
https://blog.golang.org/laws-of-reflection
How slow is Go’s reflection effectively?
https://groups.google.com/forum/#!topic/golang-nuts/HcfutSkJVoY
Unsafe in Go 甘美な世界
https://techblog.ca-reward.co.jp/2016/08/post-117.html

goroutineを調べたときに深掘りしたときに調べたまとめ

並行処理プログラミングのモデル

Shared memory

いわゆるプログラミング言語のランタイムによるアプリケーションスレッド(グリーンスレッド)である
同じプロセス(LWP)内でランタイムによりスイッチされながら実行される並行化の仕組みなので、マルチコアにスケールはしない

[同じプロセス(LWP)内で動く = メモリ空間を共有する]ためグローバルオブジェクトなどへの共有メモリアクセスを制限するため、ランタイム側で実行中のアプリケーションスレッドにロックを取得させている
ロックを取得・開放を繰り返して、スイッチさせながら複数のアプリケーションスレッドを実行しているためCPUバウンドの処理の場合はパフォーマンスは改善しない(むしろスイッチコストがかかるため悪くなる)

ただし、IOバウンドの処理の場合は、IO waitの時にロックが開放されるため効率よく並列化できる。
ネットワークIOやファイルIOを多重化する場合は、アプリケーションスレッドでも効率的に並列化できる

Message passing

Shared memoryがメモリアドレスを共有するのに対して、Message passingは共有しない
データをメッセージとしてやり取りすることにより、送り手と受け手の中でのみメモリ空間を論理的に管理する(送り手と受け手のメモリ空間をライブラリレベルで論理的に管理する)
actor modelが有名

Implicit Interaction

並列化をプログラミングコードレベルでは意識せずに、コンパイラインタプリターで暗黙的に実現する。 プログラマは並列化を意識せずにコードを書くが、コンパイル時に並列実行できるようなコードに変換される(インタプリタの場合は実行時)

並列プログラミングにおける問題のカテゴリ

タスク並列化

データ並列化

暗黙的な並列化

用語

コルーチン

サブルーチンが手続き全体を処理する塊に対して、途中で明示的に実行を停止して制御を返すことができる処理
Pythonで言うyield文を使ったジェネレータ的な

goroutine

CSP (Communicating Sequential Processes)という理論にもとづいている

  • goroutineアプリケーションスレッドのスケジューリング
  • スタック管理
  • ネットワークIO

goroutine は並行性(並列性ではない)を扱いやすくするための機能です。複数スレッドで独立した関数を多重化して coroutine のように実行するというアイデアは以前からありました。 ブロッキングするシステムコールを呼び出したときなどで、ある coroutine がブロックするとき、ランタイムは自動的に OS の同一システムスレッド上で他の coroutine が一緒にブロックされないように、実行可能な別のスレッド上に移動します。プログラマがこれを意識しない、これが重要な点です

軽量スレッドと捉えるよりも、内部的にはジェネレータみたいな呼び出し待ちををランタイムがスケジューリングしてるイメージなのかな。
だからcoroutineをもじって、goroutineなのかな

http requestハンドリングでのgoroutine

golangの標準パッケージのhttp serverの実装はgoroutine per request(connection)になってた(http/server.go#2668)
libuvのような非同期IOを使ったコールバックよりも、goroutineによる並行化の戦略をとってるっぽい
そういうもんなんだろうか、、、?

 参考

Parallel programming model
https://en.wikipedia.org/wiki/Parallel_programming_model

Go 言語の goroutine と channel についての考察
http://qiita.com/izariuo440/items/9e1b1faabcee6e2e94c0

イベントループなしでのハイパフォーマンス – C10K問題へのGoの回答
http://postd.cc/performance-without-the-event-loop/

Coroutine
http://qiita.com/fujimisakari/items/811e350cbaeb45b6165e

Go の並行処理
http://jxck.hatenablog.com/entry/20130414/1365960707

「サーバ書くなら epoll 使うべき」は、今でも正しいのか
http://developer.cybozu.co.jp/archives/kazuho/2009/09/epoll-bac0.html

Linuxにおけるプロセス/スレッドの調査とか学習とか

概念的・理論的な意味におけるプロセスとスレッド

プロセスとはプログラムコードやメモリ空間などを含めた実行処理のインスタンスである
スレッドとはプロセス内でメモリを共有し、並行化するためのより細かい単位である

Linuxにおけるプロセスとスレッド

プロセスは概念的なプロセスをそのまま実装されたもの
プロセス内で並列・並行化するためのスレッドは2つの意味がある

  • 軽量プロセス(LWP)
    プロセス内でスレッドを実現するが、スレッドの実行スケジュールはOSのスケジューラが行う なので、OSスケジューラから見たら、プロセスとスレッド(LWP)は同じ単位になる
    OSのスケジューラを使うので、マルチコアにおけるCPU資源の割り当てが可能

  • ユーザースレッド(アプリケーションスレッド)
    ユーザ空間で 実装 されたスレッド機構
    実際は プロセス - LWP - ユーザースレッド という紐付けになる
    ユーザ空間で実装されたランタイムでスケジューリングされるので、プロセス内でのタスク切り替えになるのでシングルコアでしか動かない

なので、 Linux上でスレッドを使って並行・並列化するという文脈の時は

  • LWPを多重化すれば、並列化(CPUコアでスケールする)
  • ユーザースレッドを多重化すれば並行化(シングルコアでタイムスライス)

ユーザー空間上の実装で並列・並行化可能という意味で、この2つの方法を区分けせずに ユーザー(空間上の)スレッド と表記するケースがある

プロセススケジューラについて

プロセススケジューラを呼び出されるタイミングは

  • CPUによる200msごとの割り込みがあった場合
  • 実行中のスレッドが明示的にスケジューラを呼び出した場合
  • 他にもあるっぽい

これらのタイミングでプロセススケジューラが呼び出されて、その時に一番優先順にが高いプロセスにタイムスライスが割り当てられる
スケジューラはCPU割り当てのスイッチも行うことから、カーネルモードで実行される

カーネルモードとユーザーモードについて(CPUモード)

CPUのアーキテクチャ(x86とか)で実装されている実行権限コントロールの仕組み

カーネルモード = 特権モード = マスターモード = スーパーバイザーモード = システムモード
と状況によって呼ばれ方が違う

システムコールなどを通じてデバイスアクセスしたりする時はカーネルによってスレッドをカーネルモードに切り替える。
この切替が行われないままのユーザーモードだとデバイス操作などに必要なカーネルメモリ空間へのアクセスはできない(例外が発生する)

カーネルモードのユーザープロセス(スレッド) のことを カーネルスレッド を表記する場合があるが、状況によっては正解、、、?
カーネルスレッドはカーネルメモリ空間で実行される = カーネルモードのCPUで処理されているスレッドはカーネルメモリ空間へアクセスできる と同意っぽい

カーネル空間/ユーザー空間について

メモリ上においてカーネルモードのプロセスのみがアクセスできるメモリ空間

カーネルスレッドについて

PIDが0のinitや割り込み処理などを行うスレッド
ユーザープロセス(スレッド)と同じようにスケジューラによってCPU割り当てされる
カーネルスレッドはメモリ空間を固定で割り当てられていない
そのためスケジューラによって切り替わる直前のユーザープロセスのユーザーメモリ空間を使う(そのためカーネルスレッドのタイムスライスの時は毎回メモリ空間が異なる)

カーネルスレッドという言葉を使う時に OSカーネルの処理を専門で扱うスレッド を指す場合と カーネルモードのユーザープロセス(スレッド) を指す場合があるので注意(ここでは前者の意味)

プロセスと軽量プロセス(LWP)とスレッドと

プロセスはプログラムコードやスタック領域などを含めた実行状態のインスタンスみたいなもの
プロセス毎に違うメモリ空間が割り当てられているため、お互いのプロセスのメモリ空間には通常アクセスできない(そのため不具合があってもプロセス間で伝搬しない)

スケジューラーによってプロセスを切り替える時に実行中のコンテキスト(スタックなど)を一度保存したあと、切り替え後のプロセスも保存してあったコンテキストを復元して処理を続行する。
そのため切り替えるたびにこの処理が必要なため切り替えコストが高い(これをコンテキストスイッチが高い)と呼ぶ

スレッドはプロセスと違い、一つのメモリ空間を使って生成される。(プロセスというメモリ領域に複数のスレッドを生成することが可能)
そのため、上記のようなメモリを退避が不要なためコンテキストスイッチのコストが低い

Linuxではプロセスを生成するときにLWPとして生成することができる。
これは実質スレッドだが、スケジューラはプロセスとして扱うのでタイムスライスのコントロールはOSのスケジューラが行う

言語ごとのプロセスとスレッドの扱いについて

go(goroutine)やpython

- プロセス
  ┃-LWP(ユーザー(空間上の)スレッド)
  ┃  └ユーザースレッド(アプリケーションスレッドと呼ぶ場合も): goroutine, python Thread
  ┃  └ユーザースレッド(アプリケーションスレッドと呼ぶ場合も): goroutine, python Thread
  ┃  └ユーザースレッド(アプリケーションスレッドと呼ぶ場合も): goroutine, python Thread

いわゆるグリーンスレッドを扱う言語
一つのプロセス(=LWP)上で、言語ランタイムによって擬似的にスレッドを生成する。 pythonや以前のRubyの場合はGIL(Global Interpreter Lock)という機構があるためパフォーマンスが出づらい(IO多重化には有効っぽい?)

pthreadやJVMのThreadの場合

- プロセス
  ┃-LWP(ユーザー(空間上の)スレッド)
  ┃  └アプリケーションスレッド(ユーザースレッドと呼ぶ場合も): pthread, JVM Thread
  ┃-LWP(ユーザー(空間上の)スレッド)
  ┃  └アプリケーションスレッド(ユーザースレッドと呼ぶ場合も): pthread, JVM Thread
  ┃-LWP(ユーザー(空間上の)スレッド)
  ┃  └アプリケーションスレッド(ユーザースレッドと呼ぶ場合も): pthread, JVM Thread

いわゆるネイティブスレッドを扱う言語
LWPとアプリケーションスレッドが1:1なので、タスクスケジュールはOSの機構を使う

参考

JavaにおけるOS上のスレッドの取り扱い

Threadのメモリモデルを色々調べていくうちにJavaのスレッドでOSスレッドとどうやって紐付いてるんだろうと思って調べた。
JavaにおけるTheradスケジューラはOSに依存するみたいな説明がされているが、要はJVMプロセス内でOSスレッドを生成してそれをwrapしている。
知識としては知っていたけど、改めて確認してみたかったメモ

public class Main {
    public static void main(String args[]) throws Exception {
        Thread.sleep(1000 * 60 * 60);  // プロセス終了しないように止めておく
    }
}


javacしてjava Mainでjavaプロセス起動してからPID確認

root@dc4d74fd6f08:/# jps
5684 Jps
5498 Main ←ここにいる

まずはjstackでjava threadを確認

root@dc4d74fd6f08:/# jstack 5498 | grep nid
"Attach Listener" #9 daemon prio=9 os_prio=0 tid=0x00007f29a0001000 nid=0x15ba waiting on condition [0x0000000000000000]
"Service Thread" #8 daemon prio=9 os_prio=0 tid=0x00007f29dc0c0000 nid=0x1587 runnable [0x0000000000000000]
"C1 CompilerThread2" #7 daemon prio=9 os_prio=0 tid=0x00007f29dc0b0800 nid=0x1586 waiting on condition [0x0000000000000000]
"C2 CompilerThread1" #6 daemon prio=9 os_prio=0 tid=0x00007f29dc0af000 nid=0x1585 waiting on condition [0x0000000000000000]
"C2 CompilerThread0" #5 daemon prio=9 os_prio=0 tid=0x00007f29dc0ac000 nid=0x1584 waiting on condition [0x0000000000000000]
"Signal Dispatcher" #4 daemon prio=9 os_prio=0 tid=0x00007f29dc0aa000 nid=0x1583 runnable [0x0000000000000000]
"Finalizer" #3 daemon prio=8 os_prio=0 tid=0x00007f29dc083800 nid=0x1582 in Object.wait() [0x00007f29c5a50000]
"Reference Handler" #2 daemon prio=10 os_prio=0 tid=0x00007f29dc07f000 nid=0x1581 in Object.wait() [0x00007f29c5b51000]
"main" #1 prio=5 os_prio=0 tid=0x00007f29dc009800 nid=0x157b waiting on condition [0x00007f29e36ea000]
"VM Thread" os_prio=0 tid=0x00007f29dc077000 nid=0x1580 runnable
"GC task thread#0 (ParallelGC)" os_prio=0 tid=0x00007f29dc01f000 nid=0x157c runnable
"GC task thread#1 (ParallelGC)" os_prio=0 tid=0x00007f29dc020800 nid=0x157d runnable
"GC task thread#2 (ParallelGC)" os_prio=0 tid=0x00007f29dc022000 nid=0x157e runnable
"GC task thread#3 (ParallelGC)" os_prio=0 tid=0x00007f29dc024000 nid=0x157f runnable
"VM Periodic Task Thread" os_prio=0 tid=0x00007f29dc0c2800 nid=0x1588 waiting on condition

root@dc4d74fd6f08:/# jstack 5498 | grep nid | wc -l
15

jstack的には15個のスレッドがあった


次にpsコマンドでOSスレッドを確認

root@dc4d74fd6f08:/# ps -feL | grep "java Main"
UID        PID  PPID   LWP  C NLWP STIME TTY          TIME CMD
root      5498     1  5498  0   16 11:36 ?        00:00:00 java Main
root      5498     1  5499  0   16 11:36 ?        00:00:00 java Main
root      5498     1  5500  0   16 11:36 ?        00:00:00 java Main
root      5498     1  5501  0   16 11:36 ?        00:00:00 java Main
root      5498     1  5502  0   16 11:36 ?        00:00:00 java Main
root      5498     1  5503  0   16 11:36 ?        00:00:00 java Main
root      5498     1  5504  0   16 11:36 ?        00:00:00 java Main
root      5498     1  5505  0   16 11:36 ?        00:00:00 java Main
root      5498     1  5506  0   16 11:36 ?        00:00:00 java Main
root      5498     1  5507  0   16 11:36 ?        00:00:00 java Main
root      5498     1  5508  0   16 11:36 ?        00:00:00 java Main
root      5498     1  5509  0   16 11:36 ?        00:00:00 java Main
root      5498     1  5510  0   16 11:36 ?        00:00:00 java Main
root      5498     1  5511  0   16 11:36 ?        00:00:00 java Main
root      5498     1  5512  0   16 11:36 ?        00:00:00 java Main
root      5498     1  5562  0   16 11:38 ?        00:00:00 java Main

root@dc4d74fd6f08:/# ps -feL | grep "java Main"| wc -l
16

ps的には16個あった


psコマンド的にはjstack比べてスレッドが一個多いのは
>root 5498 1 5498 0 16 11:36 ? 00:00:00 java Main
これが大元のjava親プロセスでメインスレッドを作るときにforkして子プロセスを作ってるっぽい(PIDとLWPが同じなので)

  • 1Processは1CPUで実行される
  • なので概念的にはProcessの中にいくらThreadを作成して並行化しようが、1CPUしか使わない
  • そこでLinuxとしてはLWP(Light Weight Process)としてメモリ共有したプロセス(軽量プロセス)を生成し、Threadとして扱う
  • 昔のLinuxはLWPがなかったので、単なるThreadだったのでマルチコアで多重スレッドにはできなかった
  • 実際、上記のps -feLの結果確認するとLWPのIDが全部違うのでOSスレッド = 軽量プロセスということになっている

スッキリした


プロセスとスレッド - Linux Kernel - FreeBSDいちゃらぶ日記