syscall Go adalah pengganti yang brilian untuk I/O tingkat rendah
Rangkuman
Kita akan mempelajari tentang system call langsung pada Go. Karena Go menawarkan compiler errors yang ketat dan GC yang kaku, jauh lebih baik untuk mengganti panggilan tingkat rendah dalam Pure Go. Untungnya, sebagian besar panggilan fungsi C telah diimplementasikan kembali sepenuhnya dalam Go, dengan cara yang baik dan kontemporer. Mari kita lihat.
System Call
System call adalah permintaan langsung ke sistem operasi. Karena sistem biasanya ditulis dengan gaya yang kaku dan kuno karena berjalan langsung pada hardware, kita perlu mempertimbangkan bahwa panggilannya harus memberikan bentuk permintaan yang ketat, dan benar. Jadi, meskipun kita tidak memerlukan beberapa variabel, kita tetap perlu mengisi ukurannya terlepas dari penggunaannya. Mari kita periksa dengan contoh yang berfungsi penuh.
Contoh Lengkap
1package main
2import (
3 "fmt"
4 "syscall"
5 "unsafe"
6)
7
8type sysinfo_t struct {
9 Uptime int64
10 Loads [3]uint64
11 Totalram uint64
12 Freeram uint64
13 Sharedram uint64
14 Bufferram uint64
15 Totalswap uint64
16 Freeswap uint64
17 Procs uint16
18 Pad uint16
19 _ [4]byte
20 Totalhigh uint64
21 Freehigh uint64
22 MemUnit uint32
23 _ [4]byte
24}
25
26func main() {
27 var info sysinfo_t
28 _, _, errno := syscall.Syscall(syscall.SYS_SYSINFO, uintptr(unsafe.Pointer(&info)), 0, 0)
29 if errno != 0 {
30 fmt.Println("sysinfo syscall failed:", errno)
31 return
32 }
33
34 scale := float64(1 << 16)
35 fmt.Printf("Uptime: %d seconds\n", info.Uptime)
36 fmt.Printf("Load Average: %.2f %.2f %.2f\n",
37 float64(info.Loads[0])/scale,
38 float64(info.Loads[1])/scale,
39 float64(info.Loads[2])/scale)
40 fmt.Printf("Memory: total=%d MB free=%d MB buffer=%d MB\n",
41 info.Totalram*uint64(info.MemUnit)/1024/1024,
42 info.Freeram*uint64(info.MemUnit)/1024/1024,
43 info.Bufferram*uint64(info.MemUnit)/1024/1024)
44 fmt.Printf("Swap: total=%d MB free=%d MB\n",
45 info.Totalswap*uint64(info.MemUnit)/1024/1024,
46 info.Freeswap*uint64(info.MemUnit)/1024/1024)
47 fmt.Printf("Processes: %d\n", info.Procs)
48}
Contoh ini mencakup semua variabel, dan mencetak informasi ekstensif dari informasi sistem saat ini.
Kita dapat membandingkan kode ini, sebagai sebuah loker dan sebuah kunci.syscall.SYS_SYSINFO adalah kunci yang membuka loker yang berada di dalam kernel.
Oleh karena itu, menggunakan kunci yang benar untuk loker adalah penting.
Apa yang akan terjadi jika kita menggunakan syscall.SYS_GETPID untuk panggilan ini?
Ini adalah kunci untuk loker yang berisi Process ID.
Ini akan mencoba mendapatkan PID dari ruang untuk informasi sistem.
Akibatnya, tidak ada informasi yang dapat dibaca dengan benar; panggilan tersebut harus dikembalikan sebagai state gagal.
Sekarang, kita perlu tahu item mana yang terkandung, dan bagaimana item tersebut diurutkan. Di slot pertama loker, kita memiliki Uptime, dengan ukuran 2^64. Jika kita mencoba membacanya dengan 2^32, urutan bit tidak dibaca sepenuhnya. Kita tidak dapat menggunakan jenis biner parsial ini kecuali kita akan menulis trik tingkat rendah.
Setelah membaca 64 bit data biner, akhirnya kita berada di slot kedua. Ini hanya dapat dibaca secara akurat ketika kita telah membaca integer berukuran 64-bit sebelumnya.
Dengan mengulangi alur yang ketat dan logis tersebut untuk mendapatkan informasi yang tepat dari suatu sistem, kita dapat menangani data yang dibaca dengan benar.
Cara melewati 'nama variabel'
Meskipun kita tidak dapat 'melewati' variabel itu sendiri, penting untuk membedakan variabel yang digunakan dan yang dibuang. Jika penggunaan program cukup jelas, lebih baik menggunakan variabel tanpa nama sebagai placeholder daripada memberi label pada setiap nilai meskipun nilainya tidak digunakan selamanya. Mari kita periksa ini dengan contoh, "Free Memory Checker"
Contoh - Free Memory Checker
Saat memeriksa Free Memory/Swaps, kita tidak memerlukan informasi lain yang menunjukkan sumber daya yang berbeda. Untuk mencapai visibilitas yang lebih baik, Anda dapat membuat variabel anonim untuk menampung ruang tertentu.
1package main
2
3import (
4 "fmt"
5 "syscall"
6 "unsafe"
7)
8
9type sysinfo_t struct {
10 _ int64
11 _ [3]uint64
12 Totalram uint64
13 Freeram uint64
14 Sharedram uint64
15 Bufferram uint64
16 Totalswap uint64
17 Freeswap uint64
18 _ uint16 // anonymous, and unused ones are marked as _
19 _ uint16
20 _ [4]byte
21 _ uint64
22 _ uint64
23 MemUnit uint32
24 _ [4]byte
25}
26
27func main() {
28 var info sysinfo_t
29 _, _, errno := syscall.Syscall(syscall.SYS_SYSINFO, uintptr(unsafe.Pointer(&info)), 0, 0)
30 if errno != 0 {
31 fmt.Println("sysinfo syscall failed:", errno)
32 return
33 }
34
35 fmt.Printf("Memory: total=%d MB free=%d MB buffer=%d MB\n",
36 info.Totalram*uint64(info.MemUnit)/1024/1024,
37 info.Freeram*uint64(info.MemUnit)/1024/1024,
38 info.Bufferram*uint64(info.MemUnit)/1024/1024)
39 fmt.Printf("Swap: total=%d MB free=%d MB\n",
40 info.Totalswap*uint64(info.MemUnit)/1024/1024,
41 info.Freeswap*uint64(info.MemUnit)/1024/1024)
42}
Akibatnya, variabel dibaca tanpa label. Meskipun nilai anonim sebenarnya disimpan ke dalam struktur, tidak ada label/tanda yang dapat dibaca pada kode.
Kesimpulan
- Menggunakan
syscalldanunsafeGo masih lebih aman daripada C/CGo - Jika Anda menulis proyek besar yang dapat diperluas dengan mudah:
- Jangan membuat variabel anonim; buat setiap nama untuk anggota.
- Jika Anda menulis proyek yang memiliki penggunaan terbatas:
- Anda dapat menggunakan variabel anonim untuk menampung ruang yang sebenarnya tidak digunakan.
syscallGo sangat kuat dan modern untuk menangani panggilan tingkat rendah