Halo para Penduduk!
Apakah Anda sudah terbiasa dengan dasar-dasar bahasa Go? Maka buku ini untuk Anda. Michalis Tsukalos akan mendemonstrasikan kemampuan bahasanya, memberikan penjelasan yang jelas dan sederhana, memberikan contoh dan menyarankan pola pemrograman yang efektif. Saat Anda menjelajahi nuansa Go, Anda akan menguasai tipe dan struktur data bahasa, serta pengemasan, konkurensi, pemrograman jaringan, desain kompilator, pengoptimalan, dan banyak lagi. Materi dan latihan di akhir setiap bab akan membantu memperkuat pengetahuan baru Anda. Materi unik adalah bab tentang pembelajaran mesin di Go, yang akan memandu Anda dari teknik statistik dasar hingga regresi dan pengelompokan. Anda akan mempelajari klasifikasi, jaringan saraf, dan teknik deteksi anomali. Di Bagian Terapan, Anda akan mempelajari cara menggunakan Go dengan Docker dan Kubernetes, Git, WebAssembly, JSON, dan banyak lagi.
Tentang apa buku ini
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-, . : -, , , -, .
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-, . : -, , , -, .
Dan lagi tentang Go-channel
Setelah kata kunci pilihan digunakan, ada beberapa cara unik untuk menggunakan saluran Go yang melakukan lebih dari apa yang Anda lihat di Bab 9. Di bagian ini, Anda akan mempelajari tentang berbagai penggunaan saluran Go.
Izinkan saya mengingatkan Anda bahwa nilai nol untuk saluran adalah nihil, dan jika Anda mengirim pesan ke saluran tertutup, program akan masuk ke mode panik. Tetapi jika Anda mencoba membaca data dari saluran tertutup, Anda akan mendapatkan nilai nol untuk saluran jenis ini. Jadi, setelah menutup saluran, Anda tidak dapat lagi menulis data ke saluran tersebut, tetapi Anda masih dapat membacanya.
Untuk saluran yang akan ditutup, tidak harus dirancang untuk hanya menerima data. Selain itu, saluran nol selalu diblokir, artinya, upaya untuk membaca atau menulis dari saluran nol akan memblokir saluran. Properti saluran ini sangat berguna ketika Anda ingin menonaktifkan cabang pernyataan pilih dengan mengatur variabel saluran ke nihil.
Akhirnya, saat mencoba menutup saluran nol, program akan menimbulkan kepanikan. Mari kita lihat contoh closeNilChannel.go:
package main
func main() {
var c chan string
close(c)
}
Menjalankan closeNilChannel.go akan menghasilkan hasil sebagai berikut:
$ go run closeNilChannel.go
panic: close of nil channel
goroutine 1 [running]:
main.main()
/Users/mtsouk/closeNilChannel.go:5 +0x2a
exit status 2
Saluran sinyal
Saluran pensinyalan adalah saluran yang digunakan hanya untuk pensinyalan. Sederhananya, saluran pensinyalan dapat digunakan ketika Anda ingin menginformasikan program lain tentang sesuatu. Saluran pensinyalan tidak perlu digunakan untuk mentransfer data.
Kanal pensinyalan tidak boleh disamakan dengan penanganan sinyal UNIX yang dibahas dalam Bab 8, saluran ini sama sekali berbeda.
Contoh kode yang menggunakan saluran pensinyalan akan dibahas nanti di bab ini.
Saluran yang disangga
Topik dari sub-bagian ini adalah pipa penyangga. Ini adalah saluran yang memungkinkan penjadwal Go mengantrekan pekerjaan dengan cepat untuk menangani lebih banyak permintaan. Selain itu, mereka dapat digunakan sebagai semaphore untuk membatasi bandwidth aplikasi.
Metode yang disajikan di sini berfungsi seperti ini: semua permintaan yang masuk dialihkan ke saluran, yang memprosesnya secara bergantian. Ketika saluran selesai memproses permintaan, ia mengirim pesan ke penelepon asli bahwa saluran tersebut siap untuk memproses permintaan baru. Dengan demikian, kapasitas buffer saluran membatasi jumlah permintaan bersamaan yang dapat disimpan saluran.
Kita akan melihat metode ini menggunakan kode program bufChannel.go sebagai contoh. Mari bagi menjadi empat bagian.
Bagian pertama dari kode bufChannel.go terlihat seperti ini:
package main
import (
"fmt"
)
Bagian kedua dari file bufChannel.go berisi kode Go berikut:
func main() {
numbers := make(chan int, 5)
counter := 10
Definisi angka yang disajikan di sini memungkinkan Anda menyimpan hingga lima bilangan bulat dalam pipa ini.
Bagian ketiga bufChannel.go berisi kode Go berikut:
for i := 0; i < counter; i++ {
select {
case numbers <- i:
default:
fmt.Println("Not enough space for", i)
}
}
Dalam kode ini, kami mencoba memasukkan sepuluh angka di saluran angka. Namun, karena bilangan hanya memiliki ruang untuk lima bilangan bulat, kita tidak dapat menyimpan kesepuluh bilangan bulat di dalamnya.
Kode Go lainnya dari bufChannel.go terlihat seperti ini:
for i := 0; i < counter+5; i++ {
select {
case num := <-numbers:
fmt.Println(num)
default:
fmt.Println("Nothing more to be done!")
break
}
}
}
Dalam kode Go ini, kami mencoba membaca konten dari saluran nomor menggunakan for loop dan pernyataan pilih. Selama ada sesuatu untuk dibaca di saluran angka, cabang pertama dari pernyataan pilih akan dieksekusi. Ketika saluran nomor kosong, cabang default dijalankan.
Menjalankan bufChannel.go akan memberikan hasil sebagai berikut:
$ 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!
Nol saluran
Di bagian ini, Anda akan belajar tentang saluran nol. Ini adalah jenis saluran khusus yang selalu diblokir. Kami akan melihat saluran ini menggunakan program nilChannel.go sebagai contoh. Mari kita pisahkan menjadi empat bagian kode.
Bagian pertama dari nilChannel.go terlihat seperti ini:
package main
import (
"fmt"
"math/rand"
"time"
)
Bagian kedua dari nilChannel.go berisi kode Go berikut:
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)
}
}
}
Di sini, menggunakan fungsi add () sebagai contoh, menunjukkan bagaimana saluran nol digunakan. Operator <-tC memblokir kanal C timer t untuk waktu yang ditentukan dalam panggilan ke waktu.NewTimer (). Jangan bingung antara saluran c, yang merupakan argumen fungsi, dengan saluran tC, yang merupakan milik timer t. Ketika waktunya habis, pengatur waktu mengirimkan nilai ke saluran tC, yang memulai pelaksanaan cabang yang sesuai dari pernyataan pilih - ini mengatur saluran c ke nihil dan menampilkan nilai variabel jumlah.
Potongan kode nilChannel.go ketiga terlihat seperti ini:
func send(c chan int) {
for {
c <- rand.Intn(10)
}
}
Tujuan dari fungsi send () adalah untuk menghasilkan nomor acak dan mengirimkannya ke saluran selama saluran tersebut terbuka.
Kode Go lainnya di nilChannel.go terlihat seperti ini:
func main() {
c := make(chan int)
go add(c)
go send(c)
time.Sleep(3 * time.Second)
}
Fungsi time.Sleep () diperlukan agar kedua goroutine memiliki cukup waktu untuk dieksekusi.
Menjalankan nilChannel.go akan menghasilkan hasil sebagai berikut:
$ go run nilChannel.go
13167523
$ go run nilChannel.go
12988362
Karena berapa kali cabang pertama dari pernyataan pilih di add () dieksekusi tidak tetap, menjalankan nilChannel.go beberapa kali akan menghasilkan hasil yang berbeda.
Saluran saluran
Saluran saluran adalah jenis variabel saluran khusus yang bekerja dengan saluran lain daripada jenis variabel biasa. Namun, Anda masih perlu mendeklarasikan tipe data untuk saluran saluran. Untuk menentukan saluran saluran, gunakan kata kunci chan dua kali berturut-turut, seperti yang ditunjukkan pada pernyataan berikut:
c1 := make(chan chan int)
Jenis saluran lain yang disajikan dalam bab ini lebih populer dan berguna daripada saluran saluran.
Kami akan membahas penggunaan saluran saluran menggunakan kode contoh yang ditemukan di file chSquare.go. Mari bagi menjadi empat bagian.
Bagian pertama dari chSquare.go terlihat seperti ini:
package main
import (
"fmt"
"os"
"strconv"
"time"
)
var times int
Bagian kedua dari chSquare.go berisi kode Go berikut:
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
}
}
Setelah menyatakan saluran biasa dengan tipe int, kita meneruskannya ke variabel saluran saluran. Kemudian, dengan menggunakan pernyataan pilih, kita mendapatkan kesempatan untuk membaca data dari saluran int biasa atau keluar dari fungsi menggunakan saluran sinyal f.
Setelah membaca satu nilai dari saluran c, kita menjalankan perulangan for yang menghitung jumlah semua bilangan bulat dari 0 ke nilai bilangan bulat yang baru saja kita baca. Kemudian kami mengirim nilai yang dihitung ke saluran int c, dan hanya itu.
Bagian ketiga dari chSquare.go berisi kode Go berikut:
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)
Di baris terakhir potongan kode ini, kami mendeklarasikan variabel saluran bernama cc. Variabel ini adalah bintang dari program ini, karena semuanya tergantung padanya. Variabel cc diteruskan ke f1 () dan digunakan di loop for berikutnya.
Kode chSquare.go Go lainnya terlihat seperti ini:
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)
}
}
Saluran f adalah saluran sinyal untuk akhir goroutine ketika semua pekerjaan sudah selesai. Instruksi ch: = <-cc memungkinkan Anda untuk mendapatkan saluran biasa dari variabel saluran untuk melewatkan nilai int di sana menggunakan operator ch <- i. Setelah itu, kita membaca data dari pipa menggunakan for loop. Fungsi f1 () diprogram untuk mengembalikan satu nilai, tetapi kita juga bisa membaca beberapa nilai. Perhatikan bahwa setiap nilai i disajikan oleh goroutine-nya sendiri.
Jenis saluran sinyal bisa apa saja, termasuk bool yang digunakan dalam kode sebelumnya dan struct {}, yang akan digunakan untuk saluran sinyal di bagian selanjutnya. Keuntungan utama saluran pensinyalan tipe struct {} adalah bahwa data tidak bisa dikirim ke saluran seperti itu, hal ini mencegah terjadinya kesalahan.
Menjalankan chSquare.go akan menghasilkan hasil seperti ini:
$ 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
Memilih urutan eksekusi goroutine
Anda tidak perlu membuat asumsi apa pun tentang urutan eksekusi goroutine. Namun, ada kalanya perlu untuk mengontrol tatanan ini. Dalam subbagian ini, Anda akan mempelajari cara melakukan ini menggunakan saluran pensinyalan.
Anda mungkin bertanya, "Mengapa membuat goroutine dan kemudian menjalankannya dalam urutan tertentu padahal lebih mudah untuk melakukan hal yang sama dengan fungsi biasa?" Jawabannya sederhana: goroutine dapat berjalan secara bersamaan dan menunggu goroutine lain selesai, sedangkan fungsi tidak bisa karena dijalankan secara berurutan.
Dalam sub-bagian ini, kita akan melihat program Go yang disebut defineOrder.go. Mari kita bagi menjadi lima bagian. Bagian pertama dari defineOrder.go terlihat seperti ini:
package main
import (
"fmt"
"time"
)
func A(a, b chan struct{}) {
<-a
fmt.Println("A()!")
time.Sleep(time.Second)
close(b)
}
Fungsi A () dikunci oleh saluran yang disimpan dalam parameter a. Segera setelah saluran ini dibuka kuncinya di main (), fungsi A () akan mulai bekerja. Akhirnya, itu akan menutup saluran b, sehingga membuka blokir fungsi lain - dalam hal ini, B ().
Bagian kedua dari defineOrder.go berisi kode Go berikut:
func B(a, b chan struct{}) {
<-a
fmt.Println("B()!")
close(b)
}
Logika fungsi B () sama dengan logika A (). Fungsi ini diblokir sampai saluran a ditutup. Kemudian melakukan tugasnya dan menutup saluran b. Perhatikan bahwa saluran a dan b merujuk ke nama parameter fungsi.
Bagian kode ketiga untuk defineOrder.go terlihat seperti ini:
func C(a chan struct{}) {
<-a
fmt.Println("C()!")
}
Fungsi C () diblokir dan menunggu saluran a ditutup sebelum memulai.
Bagian keempat dari defineOrder.go berisi kode berikut:
func main() {
x := make(chan struct{})
y := make(chan struct{})
z := make(chan struct{})
Ketiga saluran ini akan menjadi parameter untuk tiga fungsi.
Cuplikan terakhir dari defineOrder.go berisi kode Go berikut:
go C(z)
go A(x, y)
go C(z)
go B(y, z)
go C(z)
close(x)
time.Sleep(3 * time.Second)
}
Di sini, program melakukan semua fungsi yang diperlukan, lalu menutup saluran x dan tidur selama tiga detik.
Menjalankan defineOrder.go akan memberikan hasil yang diinginkan, meskipun fungsi C () akan dipanggil beberapa kali:
$ go run defineOrder.go
A()!
B()!
C()!
C()!
C()!
Memanggil C () beberapa kali sebagai goroutine tidak akan menimbulkan masalah, karena C () tidak menutup saluran apa pun. Namun jika Anda memanggil A () atau B () lebih dari satu kali, kemungkinan besar akan muncul pesan error, misalnya:
$ 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
Seperti yang Anda lihat, di sini fungsi A () dipanggil dua kali. Namun, ketika A () menutup saluran, salah satu goroutine mendeteksi bahwa saluran sudah ditutup dan menciptakan situasi panik ketika mencoba menutup saluran itu lagi. Jika kita mencoba memanggil fungsi B () lebih dari sekali, kita mendapatkan situasi panik yang serupa.
Bagaimana tidak menggunakan goroutine
Di bagian ini, Anda akan mempelajari cara naif dalam mengurutkan bilangan asli menggunakan goroutine. Program yang akan kita lihat disebut sillySort.go. Mari bagi menjadi dua bagian. Bagian pertama dari sillySort.go terlihat seperti ini:
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
}
Bagian kedua dari sillySort.go berisi kode Go berikut:
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()
}
Pengurutan dilakukan dengan memanggil fungsi time.Sleep () - semakin besar bilangan asli, semakin lama waktu yang dibutuhkan sebelum operator fmt.Print () dijalankan!
Menjalankan sillySort.go akan menghasilkan hasil seperti ini:
$ 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
tentang Penulis
Mihalis Tsoukalos adalah administrator UNIX, programmer, administrator database dan ahli matematika. Suka menulis buku dan artikel teknis, mempelajari sesuatu yang baru. Selain buku ini, Michalis telah menulis Pemrograman Sistem Go serta lebih dari 250 artikel teknis untuk banyak majalah, termasuk Sys Admin, MacTech, Pengguna dan Pengembang Linux, Usenix; login:, Format Linux, dan Jurnal Linux. Minat penelitian Michalis adalah database, visualisasi, statistik, dan pembelajaran mesin.
Tentang editor ilmiah
Mat Ryer telah menulis program komputer sejak usia enam tahun: pertama pada BASIC untuk ZX Spectrum, dan kemudian, dengan ayahnya, pada AmigaBASIC dan AMOS untuk Commodore Amiga. Dia menghabiskan banyak waktu untuk menyalin kode secara manual dari majalah Amiga Format, mengubah nilai variabel atau referensi pernyataan GOTO untuk melihat apa hasilnya. Semangat eksplorasi dan obsesi yang sama dengan pemrograman membuat Matt, 18 tahun, bekerja untuk sebuah organisasi lokal di Mansfield, Inggris, di mana ia mulai membangun situs web dan layanan online lainnya.
Setelah beberapa tahun bekerja dengan berbagai teknologi di berbagai bidang, tidak hanya di London, tetapi di seluruh dunia, Mat mengalihkan perhatiannya ke bahasa pemrograman sistem baru yang disebut Go, yang pertama kali digunakan di Google. Karena Go memecahkan masalah teknis yang sangat relevan dan mutakhir, Mat mulai menggunakan bahasa tersebut untuk pemecahan masalah ketika Go masih dalam versi beta dan terus memprogramnya sejak saat itu. Mat telah mengerjakan berbagai proyek open source, membuat beberapa paket Go, termasuk Testify, Moq, Silk, dan Is, serta toolkit pengembang MacOS BitBar.
Sejak 2018, Mat telah menjadi salah satu pendiri Machine Box, tetapi dia masih berpartisipasi dalam konferensi, menulis tentang Go di blognya, dan merupakan anggota aktif komunitas Go.
»Rincian lebih lanjut tentang buku dapat ditemukan di situs penerbit
» Daftar Isi
» Kutipan
Untuk Habitants diskon 25% untuk kupon - Golang
Setelah pembayaran untuk versi kertas buku, e-book dikirim ke email.