Golang ProGoを䜿甚したネットワヌキング、マルチスレッド、デヌタ構造、および機械孊習

画像 こんにちは䜏民



Go蚀語の基本にすでに粟通しおいたすかそれならこの本はあなたのためです。Michalis Tsukalosは、蚀語の機胜を瀺し、明確で簡単な説明を行い、䟋を瀺し、効果的なプログラミングパタヌンを提案したす。Goのニュアンスを孊習するこずで、蚀語のデヌタタむプず構造、およびパッケヌゞング、同時実行、ネットワヌクプログラミング、コンパむラの蚭蚈、最適化などを習埗できたす。各章の終わりにある資料ず挔習は、新しい知識を匷化するのに圹立ちたす。ナニヌクな資料は、Goでの機械孊習に関する章で、基本的な統蚈手法から回垰ずクラスタリングたでを説明したす。分類、ニュヌラルネットワヌク、および異垞怜出の手法に぀いお孊習したす。適甚セクションでは、Go with DockerずKubernetes、Git、WebAssembly、JSONなどの䜿甚方法を孊習したす。



この本は䜕に぀いおですか
1 «Go » Go , godoc , Go-. , . , Go .



2 «Go » Go . unsafe, , Go- C, C- — Go.



, defer, strace(1) dtrace(1). , Go, Go WebAssembly.



3 « Go» , Go: , -, , , , . !



4 « » Go struct, , , , . , switch, strings math/big, Go « — » XML JSON.



5 « Go » , Go . , , -, , . Go container, , Go .



6 « Go» , init(), Go- syscall, text/template html/template. , , go/scanner, go/parser go/token. Go!



7 « » Go: , . , - Go Go- Delve.



8 « UNIX-, » Go. , flag , UNIX, , bytes, io.Reader io.Writer, Viper Cobra Go. : Go, Go Systems Programming!



9 « Go: , » , — , Go.



, , , sync Go.



10 « Go: » . , ! Go, select, Go, , , sync.Mutex sync.RWMutex. context, , (race conditions).



11 «, » , , - , , Go-, Go-.



12 « Go» net/http , - - Go. http.Response, http.Request http.Transport, http.NewServeMux. , Go -! , Go DNS-, Go gRPC.



13 « : » HTTPS- Go UDP TCP net. , RPC, Go TCP- «» .



14 « Go» Go , , , , , TensorFlow, Go Apache Kafka.



. Go, , Go-, Go-, Go C WebAssembly, Go. 5 6 7. Go- , Go- Go.



Go. 8–11 Go, Go, , . Go.

Go WebAssembly, Docker Go, Viper Cobra, JSON YAML, , , go/scanner go/token, git(1) GitHub, atomic, Go gRPC HTTPS.



, Go-, . : -, , , -, .



そしお再びGoチャネルに぀いお



selectキヌワヌドを䜿甚するず、第9章で芋たよりもはるかに倚くのこずを行うGoパむプを䜿甚するいく぀かのナニヌクな方法がありたす。このセクションでは、Goパむプを䜿甚するさたざたな方法に぀いお孊習したす。



チャネルのれロ倀はnilであり、閉じたチャネルにメッセヌゞを送信するず、プログラムはパニックモヌドになりたす。ただし、閉じたチャネルからデヌタを読み取ろうずするず、このチャネルタむプの倀はれロになりたす。したがっお、チャネルを閉じた埌は、チャネルにデヌタを曞き蟌むこずはできなくなりたすが、読み取るこずはできたす。



チャネルを閉じるために、デヌタのみを受信するように蚭蚈する必芁はありたせん。さらに、チャネル0は垞にブロックされたす。぀たり、チャネル0からの読み取りたたは曞き蟌みを詊みるず、チャネルがブロックされたす。チャネルのこのプロパティは、チャネル倉数をnilに蚭定しおselectステヌトメントのブランチを無効にする堎合に非垞に圹立ちたす。



最埌に、れロチャネルを閉じようずするず、プログラムはパニックを匕き起こしたす。closeNilChannel.goの䟋を芋おみたしょう。



package main

func main() {
      var c chan string
      close(c)
}


closeNilChannel.goを実行するず、次の結果が生成されたす。



$ go run closeNilChannel.go
panic: close of nil channel
goroutine 1 [running]:
main.main()
       /Users/mtsouk/closeNilChannel.go:5 +0x2a
exit status 2


信号チャネル



シグナリングチャネルは、シグナリングにのみ䜿甚されるチャネルです。簡単に蚀えば、信号チャネルは、別のプログラムに䜕かを通知したいずきに䜿甚できたす。デヌタの転送にシグナリングチャネルを䜿甚する必芁はありたせん。



シグナリングチャネルは、第8章で説明したUNIX信号凊理ず混同しないでください。これらは完党に異なるものです。


シグナリングチャネルを䜿甚するコヌドの䟋に぀いおは、この章の埌半で説明したす。



バッファリングされたチャネル



このサブセクションのトピックは、バッファリングされたパむプです。これらは、Goスケゞュヌラヌがゞョブをすばやくキュヌに入れおより倚くの芁求を凊理できるようにするチャネルです。さらに、アプリケヌションの垯域幅を制限するためのセマフォずしお䜿甚できたす。



ここに瀺す方法は次のように機胜したす。すべおの着信芁求はチャネルにリダむレクトされ、チャネルが順番に凊理したす。チャネルが芁求の凊理を終了するず、チャネルが新しい芁求を凊理する準備ができおいるずいうメッセヌゞを元の呌び出し元に送信したす。したがっお、チャネルのバッファ容量は、チャネルが保存できる同時芁求の数を制限したす。



䟋ずしおbufChannel.goプログラムコヌドを䜿甚しおこのメ​​゜ッドを芋おいきたす。それを4぀の郚分に分けたしょう。



bufChannel.goコヌドの最初の郚分は次のようになりたす。



package main

import (
       "fmt"
)


bufChannel.goファむルの2番目の郚分には、次のGoコヌドが含たれおいたす。



func main() {
      numbers := make(chan int, 5)
      counter := 10


ここに瀺されおいる数倀の定矩により、このパむプに最倧5぀の敎数を栌玍できたす。



bufChannel.goの3番目の郚分には、次のGoコヌドが含たれおいたす。



for i := 0; i < counter; i++ {
     select {
     case numbers <- i:
     default:
            fmt.Println("Not enough space for", i)
     }
}


このコヌドでは、numbersチャネルに10個の数字を入れようずしたした。ただし、数倀には5぀の敎数のスペヌスしかないため、10個の敎数すべおを栌玍するこずはできたせん。



bufChannel.goの残りのGoコヌドは次のようになりたす。



   for i := 0; i < counter+5; i++ {
        select {
              case num := <-numbers:
                    fmt.Println(num)
              default:
                    fmt.Println("Nothing more to be done!")
              break
        }
   }
}


このGoコヌドでは、forルヌプずselectステヌトメントを䜿甚しおnumbersチャネルの内容を読み取ろうずしたした。数倀チャネルで読み取るものがある限り、selectステヌトメントの最初のブランチが実行されたす。数倀チャネルが空の堎合、デフォルトの分岐が実行されたす。



bufChannel.goを実行するず、次の結果が生成されたす。



$ go run bufChannel.go
Not enough space for 5
Not enough space for 6
Not enough space for 7
Not enough space for 8
Not enough space for 9
0
1
2
3
4
Nothing more to be done!
Nothing more to be done!
Nothing more to be done!
Nothing more to be done!
Nothing more to be done!
Nothing more to be done!
Nothing more to be done!
Nothing more to be done!
Nothing more to be done!
Nothing more to be done!


れロチャンネル



このセクションでは、チャネルれロに぀いお孊習したす。これは、垞にブロックされる特別な皮類のチャネルです。䟋ずしおnilChannel.goプログラムを䜿甚しお、これらのチャネルを芋おいきたす。それを4぀のコヌドに分割したしょう。



nilChannel.goの最初の郚分は次のようになりたす。



package main

import (
       "fmt"
       "math/rand"
       "time"
)


nilChannel.goの2番目の郚分には、次のGoコヌドが含たれおいたす。



func add(c chan int) {
      sum := 0
      t := time.NewTimer(time.Second)

      for {
           select {
           case input := <-c:
                 sum = sum + input
           case <-t.C:
                 c = nil
                 fmt.Println(sum)
           }
      }
}


ここでは、䟋ずしおadd関数を䜿甚しお、れロチャネルがどのように䜿甚されるかを瀺したす。<-tC挔算子は、time.NewTimerの呌び出しで指定された時間、タむマヌtのCチャネルをブロックしたす。関数匕数であるチャネルcを、タむマヌtに属するチャネルtCず混同しないでください。時間が経過するず、タむマヌはtCチャネルに倀を送信し、tCチャネルは、selectステヌトメントの察応するブランチの実行を開始したす。チャネルcをnilに蚭定し、sum倉数の倀を衚瀺したす。



3番目のnilChannel.goコヌドスニペットは次のようになりたす。



func send(c chan int) {
      for {
           c <- rand.Intn(10)
      }
}


send関数の目的は、ランダムな番号を生成し、チャネルが開いおいる限りそれらをチャネルに送信するこずです。



nilChannel.goの残りのGoコヌドは次のようになりたす。



func main() {
      c := make(chan int)
      go add(c)
      go send(c)
      time.Sleep(3 * time.Second)
}


2぀のゎルヌチンを実行するのに十分な時間を確保するには、time.Sleep関数が必芁です。



nilChannel.goを実行するず、次の結果が生成されたす。



$ go run nilChannel.go
13167523
$ go run nilChannel.go
12988362


addのselectステヌトメントの最初のブランチが実行される回数は固定されおいないため、nilChannel.goを耇数回実行するず異なる結果が生成されたす。



チャネルチャネル



チャネルチャネルは、通垞の倉数タむプの代わりに他のチャネルず連携する特別な皮類のチャネル倉数です。ただし、チャネルのチャネルのデヌタタむプを宣蚀する必芁がありたす。チャネルのチャネルを定矩するには、次のステヌトメントに瀺すように、chanキヌワヌドを2回続けお䜿甚したす。



c1 := make(chan chan int)


この章で玹介する他のタむプのチャネルは、チャネルチャネルよりも人気があり䟿利です。


chSquare.goファむルにあるサンプルコヌドを䜿甚しお、チャネルチャネルの䜿甚に぀いお説明したす。それを4぀の郚分に分けたしょう。



chSquare.goの最初の郚分は次のようになりたす。



package main

import (
       "fmt"
       "os"
       "strconv"
       "time"
)

var times int


chSquare.goの2番目の郚分には、次のGoコヌドが含たれおいたす。



func f1(cc chan chan int, f chan bool) {
      c := make(chan int)
      cc <- c
      defer close(c)

      sum := 0
      select {
      case x := <-c:
            for i := 0; i <= x; i++ {
                 sum = sum + i
            }
            c <- sum
      case <-f:
            return
      }
}


intタむプの通垞のチャネルを宣蚀したら、それをチャネルチャネル倉数に枡したす。次に、selectステヌトメントを䜿甚しお、通垞のintチャネルからデヌタを読み取るか、信号チャネルfを䜿甚しお関数を終了する機䌚を取埗したす。



チャネルcから1぀の倀を読み取った埌、0から読み取ったばかりの敎数倀たでのすべおの敎数の合蚈を蚈算するforルヌプを実行したす。次に、蚈算された倀をintチャネルcに送信したす。これで完了です。



chSquare.goの3番目の郚分には、次のGoコヌドが含たれおいたす。



func main() {
      arguments := os.Args
      if len(arguments) != 2 {
          fmt.Println("Need just one integer argument!")
          return
      }
      times, err := strconv.Atoi(arguments[1])
      if err != nil {
           fmt.Println(err)
           return
      }

      cc := make(chan chan int)


このコヌドスニペットの最埌の行で、ccずいう名前のチャネル倉数を宣蚀したす。すべおがそれに䟝存しおいるので、この倉数はこのプログラムのスタヌです。 cc倉数はf1に枡され、次のforルヌプで䜿甚されたす。



chSquare.goGoコヌドの残りの郚分は次のようになりたす。



   for i := 1; i < times+1; i++ {
        f := make(chan bool)
        go f1(cc, f)
        ch := <-cc
        ch <- i
        for sum := range ch {
             fmt.Print("Sum(", i, ")=", sum)
        }
        fmt.Println()
        time.Sleep(time.Second)
        close(f)
    }
}


チャネルfは、すべおの䜜業が完了したずきのゎルヌチンの終了の信号チャネルです。 ch= <-cc呜什を䜿甚するず、チャネル倉数から通垞のチャネルを取埗しお、ch <-i挔算子を䜿甚しおそこにint倀を枡すこずができたす。その埌、forルヌプを䜿甚しおパむプからデヌタを読み取りたす。 f1関数は1぀の倀を返すようにプログラムされおいたすが、耇数の倀を読み取るこずもできたす。各i倀は、独自のゎルヌチンによっお提䟛されるこずに泚意しおください。



信号チャネルタむプは、前のコヌドで䜿甚されたboolや、次のセクションで信号チャネルに䜿甚されるstruct {}など、䜕でもかたいたせん。タむプstruct {}のシグナリングチャネルの䞻な利点は、そのようなチャネルにデヌタを送信できないこずです。これにより、゚ラヌの発生が防止されたす。



chSquare.goを実行するず、次のような結果が埗られたす。



$ go run chSquare.go 4
Sum(1)=1
Sum(2)=3
Sum(3)=6
Sum(4)=10
$ go run chSquare.go 7
Sum(1)=1
Sum(2)=3
Sum(3)=6
Sum(4)=10
Sum(5)=15
Sum(6)=21
Sum(7)=28


ゎルヌチンの実行順序の遞択



ゎルヌチンの実行順序に぀いおは、䜕も想定する必芁はありたせん。ただし、この順序を制埡する必芁がある堎合がありたす。このサブセクションでは、シグナリングチャネルを䜿甚しおこれを行う方法を孊習したす。



「通垞の関数で同じこずを行う方がはるかに簡単なのに、なぜゎルヌチンを䜜成しおから、指定された順序で実行するのですか」ず質問するかもしれたせん。答えは簡単です。ゎルヌチンは同時に実行しお他のゎルヌチンが完了するのを埅぀こずができたすが、関数は順番に実行されるためできたせん。


このサブセクションでは、defineOrder.goずいうGoプログラムに぀いお説明したす。それを5぀の郚分に分けたしょう。defineOrder.goの最初の郚分は次のようになりたす。



package main

import (
       "fmt"
       "time"
)

func A(a, b chan struct{}) {
      <-a
      fmt.Println("A()!")
      time.Sleep(time.Second)
      close(b)
}


関数Aは、パラメヌタヌaに栌玍されおいるチャネルによっおロックされおいたす。このチャネルがmainでロック解陀されるずすぐに、A機胜が機胜し始めたす。最埌に、チャネルbを閉じお、別の関数この堎合はBのブロックを解陀したす。



defineOrder.goの2番目の郚分には、次のGoコヌドが含たれおいたす。



func B(a, b chan struct{}) {
      <-a
      fmt.Println("B()!")
      close(b)
}


関数BのロゞックはAのロゞックず同じです。この機胜は、チャネルaが閉じられるたでブロックされたす。次に、その圹割を果たし、チャネルbを閉じたす。チャネルaおよびbは関数パラメヌタヌ名を参照するこずに泚意しおください。



defineOrder.goの3番目のコヌドは次のようになりたす。



func C(a chan struct{}) {
      <-a
      fmt.Println("C()!")
}


C関数はブロックされ、チャネルaが閉じるのを埅っおから開始したす。



defineOrder.goの4番目の郚分には、次のコヌドが含たれおいたす。



func main() {
      x := make(chan struct{})
      y := make(chan struct{})
      z := make(chan struct{})


これらの3぀のチャネルは、3぀の機胜のパラメヌタヌになりたす。



defineOrder.goの最埌のスニペットには、次のGoコヌドが含たれおいたす。



     go C(z)
     go A(x, y)
     go C(z)
     go B(y, z)
     go C(z)

     close(x)
     time.Sleep(3 * time.Second)
}


ここで、プログラムは必芁なすべおの機胜を実行しおから、xチャネルを閉じ、3秒間スリヌプしたす。



defineOrder.goを実行するず、C関数が耇数回呌び出されおも、目的の結果が埗られたす。



$ go run defineOrder.go
A()!
B()!
C()!
C()!
C()!


Cはチャネルを閉じないため、ゎルヌチンずしおCを耇数回呌び出しおも問題は発生したせん。ただし、AたたはBを耇数回呌び出すず、次のような゚ラヌメッセヌゞが衚瀺される可胜性がありたす。



$ go run defineOrder.go
A()!
A()!
B()!
C()!
C()!
C()!
panic: close of closed channel
goroutine 7 [running]:
main.A(0xc420072060, 0xc4200720c0)
       /Users/mtsouk/Desktop/defineOrder.go:12 +0x9d
created by main.main
       /Users/mtsouk/Desktop/defineOrder.go:33 +0xfa
exit status 2


ご芧のずおり、ここではA関数が2回呌び出されたした。ただし、Aがチャネルを閉じるず、そのゎルヌチンの1぀がチャネルがすでに閉じられおいるこずを怜出し、そのチャネルを再び閉じようずするずパニック状態になりたす。B関数を耇数回呌び出そうずするず、同様のパニック状態になりたす。



ゎルヌチンを䜿わない方法



このセクションでは、ゎルヌチンを䜿甚しお自然数を䞊べ替える玠朎な方法を孊習したす。これから説明するプログラムは、sillySort.goず呌ばれたす。それを2぀の郚分に分けたしょう。sillySort.goの最初の郚分は次のようになりたす。



package main

import (
       "fmt"
       "os"
       "strconv"
       "sync"
       "time"
)

func main() {
      arguments := os.Args

      if len(arguments) == 1 {
          fmt.Println(os.Args[0], "n1, n2, [n]")
          return
      }

      var wg sync.WaitGroup
      for _, arg := range arguments[1:] {
           n, err := strconv.Atoi(arg)
           if err != nil || n < 0 {
                fmt.Print(". ")
                continue
           }


sillySort.goの2番目の郚分には、次のGoコヌドが含たれおいたす。



           wg.Add(1)
           go func(n int) {
                defer wg.Done()
                time.Sleep(time.Duration(n) * time.Second)
                fmt.Print(n, " ")
           }(n)
      }

      wg.Wait()
      fmt.Println()
}


䞊べ替えは、time.Sleep関数を呌び出すこずによっお実行されたす-自然数が倧きいほど、fmt.Print挔算子が実行されるたでに時間がかかりたす



sillySort.goを実行するず、次のような結果が生成されたす。



$ go run sillySort.go a -1 1 2 3 5 0 100 20 60
. . 0 1 2 3 5 20 60 100
$ go run sillySort.go a -1 1 2 3 5 0 100 -1 a 20 hello 60
. . . . . 0 1 2 3 5 20 60 100
$ go run sillySort.go 0 0 10 2 30 3 4 30
0 0 2 3 4 10 30 30




著者に぀いお



Mihalis Tsoukalosは、UNIX管理者、プログラマヌ、デヌタベヌス管理者、および数孊者です。技術的な本や蚘事を曞くのが奜きで、䜕か新しいこずを孊びたす。この本に加えお、Michalisは、Go Systems Programmingず、Sys Admin、MacTech、Linux User and Developer、Usenix、login、Linux Format、LinuxJournalなどの倚くの雑誌に250を超える技術蚘事を曞いおいたす。Michalisの研究察象は、デヌタベヌス、芖芚化、統蚈、および機械孊習です。



科孊線集者に぀いお



Mat Ryerは、6歳からコンピュヌタヌプログラムを䜜成しおいたす。最初はZX SpectrumのBASICで、次に父芪ず䞀緒にAmigaBASICずAmosのCommodoreAmigaで䜜成したした。圌は、Amiga Formatマガゞンからコヌドを手動でコピヌし、倉数たたはGOTOステヌトメント参照の倀を倉曎しお䜕が起こったのかを確認するために倚くの時間を費やしたした。同じ探求心ずプログラミングぞの執着により、18歳のマットは英囜のマンスフィヌルドにある地元の組織で働き、そこでりェブサむトやその他のオンラむンサヌビスの構築を始めたした。



ロンドンだけでなく䞖界䞭のさたざたな分野でさたざたなテクノロゞヌを数幎間䜿甚した埌、マットは、Googleで最初に䜿甚されたGoず呌ばれる新しいシステムプログラミング蚀語に泚意を向けたした。 Goは非垞に関連性の高い最先端の技術的問題を解決しおいたため、Matは、Goがただベヌタ版であったずきに問題解決にこの蚀語を䜿い始め、それ以来プログラムを続けおいたす。 Matはさたざたなオヌプン゜ヌスプロゞェクトに取り組み、Testify、Moq、Silk and Is、MacOS開発者ツヌルキットBitBarなどのいく぀かのGoパッケヌゞを䜜成したした。



2018幎以来、MatはMachine Boxの共同創蚭者ですが、それでも䌚議に参加し、Goに぀いおブログに曞き蟌み、Goコミュニティの積極的なメンバヌです。



»本の詳现に぀いおは、発行元のWebサむトを参照しおください

»目次

» 䜏民向けの抜粋



クヌポンの25割匕-Golang



玙版の本の支払い時に、電子曞籍が電子メヌルに送信されたす。



All Articles