Go syscall on loistava korvike matalan tason I/O:lle
Yhteenveto
Opimme suorista järjestelmäkutsuista Go-kielellä. Koska Go tarjoaa tiukat kääntäjävirheet ja jäykän GC:n, on paljon parempi korvata matalan tason kutsut puhtaalla Go-kielellä. Onneksi suurin osa C-funktiokutsuista on toteutettu Go-kielellä uudelleen täysin, hyvällä ja nykyaikaisella tavalla. Tarkastellaan sitä.
Järjestelmäkutsu
Järjestelmäkutsu on suora pyyntö käyttöjärjestelmälle. Koska järjestelmä on yleensä kirjoitettu jäykällä, vanhanaikaisella tyylillä, koska se toimii suoraan laitteistolla, meidän on otettava huomioon, että sen kutsun on toimitettava pyyntö tiukassa ja oikeassa muodossa. Joten, vaikka emme tarvitsisi joitakin muuttujia, meidän on silti täytettävä koko riippumatta käytöstä. Tarkastellaan tätä täysin toimivalla esimerkillä.
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 // Kutsu sysinfo-järjestelmäkutsua
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 scale := float64(1 << 16)
36 fmt.Printf("Uptime: %d seconds\n", info.Uptime)
37 fmt.Printf("Load Average: %.2f %.2f %.2f\n",
38 float64(info.Loads[0])/scale,
39 float64(info.Loads[1])/scale,
40 float64(info.Loads[2])/scale)
41 fmt.Printf("Memory: total=%d MB free=%d MB buffer=%d MB\n",
42 info.Totalram*uint64(info.MemUnit)/1024/1024,
43 info.Freeram*uint64(info.MemUnit)/1024/1024,
44 info.Bufferram*uint64(info.MemUnit)/1024/1024)
45 fmt.Printf("Swap: total=%d MB free=%d MB\n",
46 info.Totalswap*uint64(info.MemUnit)/1024/1024,
47 info.Freeswap*uint64(info.MemUnit)/1024/1024)
48 fmt.Printf("Processes: %d\n", info.Procs)
49}
Tämä esimerkki sisältää kaikki muuttujat ja tulostaa kattavan tiedon nykyisistä järjestelmätiedoista.
Voimme verrata tätä koodia lukkoon ja avaimeen.syscall.SYS_SYSINFO on avain, joka avaa lukon, joka on ytimen sisällä.
Siksi oikean avaimen käyttö lukkoon on tärkeää.
Mitä tapahtuu, jos käytämme syscall.SYS_GETPID-kutsua tähän tarkoitukseen?
Tämä on avain lukkoon, joka sisältää prosessin ID:n.
Tämä yrittää hakea PID:n järjestelmätietojen tilasta.
Tämän seurauksena mitään tietoja ei voida lukea oikein; kutsun on palautettava epäonnistunut tila.
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ä, ellemme aio kirjoittaa matalan tason temppuja.
Luettuaan 64 bittiä binääritietoa olemme lopulta toisessa paikassa. Se voidaan lukea tarkasti vain, kun olemme lukeneet edellisen 64-bittisen kokonaisluvun.
Toistamalla näitä tiukkoja ja loogisia virtoja oikean tiedon saamiseksi järjestelmästä voimme käsitellä luettua dataa 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 paikanpitäjinä kuin nimetä jokaista arvoa, vaikka niitä ei koskaan käytettäisikään. Tarkastellaan tätä esimerkkiä, "Vapaan muistin tarkistaja".
Esimerkki - Vapaan muistin tarkistaja
Tarkistaessamme vapaata muistia/vaihtotiedostoja 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 // Anonyymi, ja käyttämättömät on merkitty _
11 _ [3]uint64
12 Totalram uint64
13 Freeram uint64
14 Sharedram uint64
15 Bufferram uint64
16 Totalswap uint64
17 Freeswap uint64
18 _ uint16
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 // Kutsu sysinfo-järjestelmäkutsua
30 _, _, errno := syscall.Syscall(syscall.SYS_SYSINFO, uintptr(unsafe.Pointer(&info)), 0, 0)
31 if errno != 0 {
32 fmt.Println("sysinfo syscall failed:", errno)
33 return
34 }
35
36 fmt.Printf("Memory: total=%d MB free=%d MB buffer=%d MB\n",
37 info.Totalram*uint64(info.MemUnit)/1024/1024,
38 info.Freeram*uint64(info.MemUnit)/1024/1024,
39 info.Bufferram*uint64(info.MemUnit)/1024/1024)
40 fmt.Printf("Swap: total=%d MB free=%d MB\n",
41 info.Totalswap*uint64(info.MemUnit)/1024/1024,
42 info.Freeswap*uint64(info.MemUnit)/1024/1024)
43}
Näin ollen muuttujat luetaan ilman tunnisteita. Vaikka anonyymit arvot tallennetaan itse asiassa rakenteeseen, koodissa ei ole tunnisteita/luettavia merkintöjä.
Johtopäätös
- Gon
syscall- jaunsafe-pakettien käyttö on edelleen turvallisempaa kuin C/CGo:n. - Jos kirjoitat valtavaa projektia, jota voidaan helposti laajentaa:
- Älä tee anonyymejä muuttujia; anna jokaiselle jäsenelle oma nimi.
- Jos kirjoitat projektia, jolla on rajoitettu käyttö:
- Voit käyttää anonyymejä muuttujia varaamaan tiloja, jotka ovat tosiasiallisesti käyttämättömiä.
- Gon
syscallon tehokas ja moderni matalan tason kutsujen käsittelyyn.