GoSuda

syscall Go adalah pengganti yang brilian untuk I/O tingkat rendah

By Yunjin Lee
views ...

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 syscall dan unsafe Go 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.
  • syscall Go sangat kuat dan modern untuk menangani panggilan tingkat rendah

Baca Lebih Lanjut

syscall unsafe x/sys/unix