Go syscall on loistava korvike matalan tason I/O:lle
Yhteenveto
Tutustumme suoraan System call -kutsuun Go-kielessä. Koska Go tarjoaa tiukat kääntäjävirheet ja jäykän GC:n, on paljon parempi korvata matalan tason kutsut puhtaassa Go:ssa (Pure Go). Onneksi suurin osa C-funktiokutsuista on toteutettu Go:ssa uudelleen täysin, hyvällä ja nykyaikaisella tavalla. Tarkastellaanpa sitä.
System Call
System call on suora pyyntö käyttöjärjestelmälle. Koska järjestelmä on yleensä kirjoitettu jäykkään, vanhanaikaiseen tyyliin, koska se suoritetaan suoraan laitteistolla, meidän on otettava huomioon, että sen kutsun on toimitettava tiukka ja oikea muoto pyynnölle. Joten, vaikka emme tarvitse joitain muuttujia, meidän on silti täytettävä koko riippumatta käytöstä. Tarkastellaan tätä täysin toimivan esimerkin avulla.
Täydellinen esimerkki
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}
Tämä esimerkki sisältää kaikki muuttujat ja tulostaa kattavat tiedot nykyisestä järjestelmätiedosta.
Voimme verrata tätä koodia lukkoon ja avaimeen.syscall.SYS_SYSINFO on avain, joka avaa ytimen sisällä olevan lukon.
Siksi oikean avaimen käyttäminen lukkoon on tärkeää.
Mitä tapahtuu, kun käytämme syscall.SYS_GETPID:tä tähän kutsuun?
Tämä on avain lukkoon, joka sisältää prosessin tunnuksen (Process ID).
Tämä yrittää saada PID:n järjestelmätietojen tilasta.
Tämän seurauksena mitään tietoa ei voida lukea oikein; kutsun on palattava epäonnistuneena tilana.
Nyt meidän on tiedettävä, mitkä kohteet sisältyvät ja miten kohteet on järjestetty. Lukon ensimmäisessä paikassa meillä on Uptime, jonka koko on 2^64. Jos yritämme lukea tämän 2^32:lla, bittijonoa ei lueta kokonaan. Emme voi käyttää tällaisia osittaisia binäärejä, ellei ole tarkoituksena kirjoittaa matalan tason temppuja.
Kun olemme lukeneet 64 bittiä binääristä dataa, olemme vihdoin toisessa paikassa. Se voidaan lukea tarkasti vain, kun olemme lukeneet edellisen 64-bittisen kokonaisluvun.
Toistamalla nämä tiukat ja loogiset kulut saadaksemme asianmukaisen tiedon järjestelmästä, voimme käsitellä luettuja tietoja asianmukaisesti.
Kuinka ohittaa 'muuttujanimet'
Vaikka emme voi 'ohittaa' itse muuttujia, on tärkeää erottaa käytetyt muuttujat hylätyistä. Jos ohjelman käyttö on riittävän selkeää, on parempi käyttää nimettömiä muuttujia paikkamerkkeinä kuin merkitä jokaista arvoa, vaikka niitä ei käytettäisi koskaan. Tarkastellaan tätä esimerkin avulla, "Vapaan muistin tarkistaja" (Free Memory Checker).
Esimerkki - Vapaan muistin tarkistaja
Kun tarkistetaan vapaata muistia/vaihtotiedostoja (Free Memory/Swaps), emme tarvitse muita tietoja, jotka osoittavat erilaisia resursseja. Paremman näkyvyyden saavuttamiseksi voit luoda anonyymejä muuttujia pitämään tiettyjä tiloja.
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}
Näin ollen muuttujat luetaan ilman tunnisteita. Vaikka anonyymit arvot tallennetaan itse asiassa rakenteeseen, koodissa ei ole tunnisteita/luettavia merkkejä.
Johtopäätös
- Go:n
syscall- jaunsafe-käyttö on edelleen turvallisempaa kuin C/CGo - Jos kirjoitat suurta projektia, jota voidaan helposti laajentaa:
- Älä tee anonyymejä muuttujia; anna jokaiselle jäsenelle nimi.
- Jos kirjoitat projektia, jolla on rajallinen käyttö:
- Voit käyttää anonyymejä muuttujia pitämään tiloja, joita ei itse asiassa käytetä.
- Go:n
syscallon tehokas ja moderni käsittelemään matalan tason kutsuja