Successfully reported this slideshow.
We use your LinkedIn profile and activity data to personalize ads and to show you more relevant ads. You can change your ad preferences anytime.

Gdg神戸go言語ハンズオンマルチスレッドで遊ぼう20120825

8,620 views

Published on

  • Be the first to comment

Gdg神戸go言語ハンズオンマルチスレッドで遊ぼう20120825

  1. 1. Go言語ハンズオンマルチスレッドで遊ぼう GDG神戸 2012/8/25 ちいといつ(twitter:titoi2)
  2. 2. Go言語の特徴 Go言語と言えば,ゴルーチン(Goroutine)を使ってマルチスレッドのプログラムが簡単に作れるのが特徴の一つ。 今日はハンズオン形式でGo言語のゴルーチンで遊びます。 キーワードはゴルーチンとチャネルです。このオポチュニティにぜひ体験して下さい。
  3. 3. 実行環境 Go言語の開発環境を構築している方は,そのままでプログラムを実行して下さい。 開発環境のない方は,こちらのアドレスにアクセス。http://play.golang.org/※実行はシングルスレッドになりますが,ゴルーチンは体験出来ます。
  4. 4. ハンズオンの進め方簡単なGo言語のプログラムを示しますので,各自入力して実行してください。ソースの意味や文法は随時説明しますが,分からないところは都度質問して下さい。
  5. 5. まずは普通のプログラムpackage mainimport "fmt"func say( s string) {/ say 関数定義 /! fmt.Println(s)}func main() { / メイン処理 /! say("Hello golang")}
  6. 6. 実行してみますHello golangと表示されました?
  7. 7. マルチスレッド化func main() {! go say("Hello golang")}メイン処理を修正します。関数呼び出しの前に go と付けるだけ。簡単スレッド化が出来ました。これをゴルーチンと言います。
  8. 8. 実行してみましょうなんにも出ません orzmainが先に終了してしまうのでsayが出力する前にプログラムが終了しています。
  9. 9. 修正しますpackage mainimport "fmt"import "runtime"func say(s string) {! fmt.Println(s)}func main() {! go say("Hello golang")! runtime.Gosched() / 他のゴルーチンを実行 /}
  10. 10. 実行してみますHello golangと表示されました?runtime.Gosched()で無理やりゴルーチンの制御を切り替えてsayが実行されるようにしました。※mainもゴルーチンの一つです。(多分)
  11. 11. 終了を待つには 無理やりsayに制御を移して実行させましたが,mainでsayの終了を待つことが出来れば問題はありません。ゴルーチンの終了待ちをするには? チャネルを使います。早速,プログラムを修正します。
  12. 12. チャネルで同期func say(s string, ch chan int) {! fmt.Println(s)! ch <- 1 / 値を送信 /}func main() {! var ch chan int / チャネル変数宣言 /! ch = make(chan int) / チャネル初期化 /! go say("Hello golang", ch)! <-ch / 受信待ち /}
  13. 13. 実行してみますHello golangと表示されました? チャネルによる通信を使って,mainとsayの同期を取ることにより,sayの終了待ちが出来ました。
  14. 14. チャネルとは・ゴルーチン(スレッド)間で通信を行うための特殊な変数。・任意の型のデータを送受信が可能。・同期と非同期(容量付き)がある。・同期チャネルを使うことによりスレッド間の同期が可能
  15. 15. チャネル変数の宣言チャネル変数の宣言方法var 変数名 chan 型名例えばint型のチャネルvar ch chan int文字列型のチャネルvar ch chan string型は何でもOK
  16. 16. チャネル変数の初期化チャネル変数を初期化するには,必ずmake関数を使います。例えばint型チャネルvar ch chan intを初期化するにはch = make(chan int)オプションで容量を指定すると非同期チャネルにch = make(chan int, 100) / 非同期チャネル /
  17. 17. 送信と受信チャネルにデータを送受信するには <- を使います。ch <- 1 / チャネルに1を送信 /a = <- ch / チャネルから受信してaに代入 /<-ch / 受信だけ行い値を捨てる /最後の値を捨てるケースは同期だけ行いたいとき。
  18. 18. 同期チャネル容量の無いチャネルを別名,同期チャネルと呼びます。あるスレッドからチャネルに送信した場合,別のスレッドがチャネルから受信するまで処理を停止します。逆に,チャネルから受信しようとしたときは,送信が行われるまで処理を停止します。
  19. 19. 同期メカニズムmainスレッド sayスレッド go say("Hello golang", ch) <-ch ちょい待って チャネル Println() ch ch <- 1 ほい 1 送ったで終了 終了
  20. 20. チャネルで同期func say(s string, ch chan int) {! fmt.Println(s)! ch <- 1 / 値を送信 /}func main() {! var ch chan int / チャネル変数宣言 /! ch = make(chan int) / チャネル初期化 /! go say("Hello golang", ch)! <-ch / ch から受信 /}
  21. 21. チャネル通信同期チャネルでスレッド間の同期が取れることがわかりました。次に,チャネルによるスレッド間通信を行います。
  22. 22. FIZZ BUZZゴルーチンを使ってFIZZ BUZZ問題を解いてみましょう。FIZZBUZZとは・1から順番に数値を出力・ただし,3の倍数なら”FIZZ”と出力・ただし,5の倍数なら”BUZZ”と出力・ただし,3と5の倍数なら”FIZZBUFF”出力。
  23. 23. FIZZ BUZZこんなゴルーチンを作ります。func fizzbuzz(in chan int, out chan string)チャネルinから数値を受け取り,3の倍数なら ”FIZZ”,5の倍数なら”BUZZ”,ただし3と5の倍数なら”FIZZBUFF”とoutに出力する。その他の数値の場合は文字列化してoutに出力する。
  24. 24. package mainimport "fmt"import "strconv"func fizzbuzz(in chan int, out chan string) {! for { / 無限ループ /! ! var n int = <-in / in から受信してnに代入 /! ! switch {! ! case n%15 == 0:! out <- "FIZZBUZZ"! ! case n%3 == 0:! out <- "FIZZ" !! ! case n%5 == 0:! out <- "BUZZ" !! ! default:! ! ! out <- strconv.Itoa(n)! ! }! }}
  25. 25. func main() {! ch := make(chan int)! out := make(chan string)! go fizzbuzz(ch, out)! for i := 1; i < 100; i++ {! ! ch <- i! ! s := <-out! ! fmt.Println(s)! }}
  26. 26. その他の機能など今回のハンズオンでは説明していませんが,チャネルには・キャパシティ付き非同期チャネル・チャネルのクローズ・for ∼ range による連続受信・select ∼ case による選択的送受信などの機能があります。
  27. 27. 展望 ハンズオンの例題は説明のための単純なものでしたが,ゴルーチンとチャネルの応用としては,サーバプログラムやパズルのソルバー,シミュレーションなどで使えるのではないでしょうか。 クロージャと組み合わせることも出来ますし,使い方を考えてみてください。 プロジェクトオイラー(http://projecteuler.net/)の問題を解くのに使ってみたりしています。

×