Go syscall, düşük seviyeli G/Ç'nin (I/O) parlak bir ikamesidir.
Özet
Go üzerinde doğrudan sistem çağrısını öğreneceğiz. Go, katı derleyici hataları ve katı GC sunduğundan, düşük seviyeli çağrıları Saf Go'da değiştirmek çok daha iyidir. Neyse ki, C işlev çağrılarının çoğu, Go'da iyi ve çağdaş bir şekilde tamamen yeniden uygulanmıştır. Buna bir göz atalım.
Sistem Çağrısı
Sistem çağrısı, işletim sistemine yapılan doğrudan bir istektir. Sistem genellikle katı, eski moda bir tarzda yazıldığı için, doğrudan bir donanım üzerinde çalıştığından, çağrısının katı ve doğru bir talep biçimi sunması gerektiğini göz önünde bulundurmalıyız. Bu nedenle, bazı değişkenlere ihtiyacımız olmasa bile, kullanıma bakılmaksızın boyutu doldurmamız gerekir. Tamamen çalışan bir örnekle kontrol edelim.
Tam Örnek
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) // sysinfo sistem çağrısı başarısız oldu:
31 return
32 }
33
34 scale := float64(1 << 16)
35 fmt.Printf("Uptime: %d seconds\n", info.Uptime) // Çalışma Süresi: %d saniye
36 fmt.Printf("Load Average: %.2f %.2f %.2f\n", // Yük Ortalaması:
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", // Bellek: toplam=%d MB boş=%d MB arabellek=%d MB
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", // Takas: toplam=%d MB boş=%d MB
45 info.Totalswap*uint64(info.MemUnit)/1024/1024,
46 info.Freeswap*uint64(info.MemUnit)/1024/1024)
47 fmt.Printf("Processes: %d\n", info.Procs) // İşlemler:
48}
Bu örnek tüm değişkenleri içerir ve mevcut sistem bilgileri hakkında kapsamlı bilgiler yazdırır.
Bu kodu bir kilitli dolap ve bir anahtar olarak karşılaştırabiliriz.syscall.SYS_SYSINFO, bir çekirdeğin içinde bulunan bir kilitli dolabın kilidini açan bir anahtardır.
Bu nedenle, bir kilitli dolap için doğru anahtarı kullanmak önemlidir.
Bu çağrı için syscall.SYS_GETPID kullandığımızda ne olacaktır?
Bu, Process ID içeren bir kilitli dolap için bir anahtardır.
Bu, sistem bilgisi için ayrılan bir alandan bir PID almaya çalışacaktır.
Sonuç olarak, hiçbir bilgi doğru bir şekilde okunamayacaktır; çağrı başarısız durumda iade edilmelidir.
Şimdi, hangi öğelerin bulunduğunu ve öğelerin nasıl sıralandığını bilmemiz gerekiyor. Bir kilitli dolabın ilk yuvasında, 2^64 boyutunda Uptime bulunur. Bunu 2^32 ile okumaya çalışırsak, bit dizisi tam olarak okunmaz. Düşük seviyeli numaralar yazmayacaksak, bu tür kısmi ikilikleri kullanamayız.
64 bitlik ikili veriyi okuduktan sonra, nihayet ikinci yuvadayız. Ancak önceki 64-bit boyutlu tamsayıyı okuduğumuzda doğru bir şekilde okunabilir.
Bir sistemden uygun bilgiyi elde etmek için bu katı ve mantıksal akışları tekrarlayarak, okunan veriyi uygun şekilde işleyebiliriz.
'Değişken adlarını' atlama
Değişkenlerin kendilerini 'atlayamasak' bile, kullanılan değişkenleri ve atılanları ayırt etmek önemlidir. Programın kullanımı yeterince açıksa, anonim değişkenleri, sonsuza kadar kullanılmayacak olsalar bile her değeri etiketlemektense, yer tutucu olarak kullanmak daha iyidir. Bunu bir örnekle, "Boş Bellek Denetleyicisi" ile kontrol edelim.
Örnek - Boş Bellek Denetleyicisi
Boş Bellek/Takasları kontrol ederken, farklı kaynakları gösteren diğer bilgilere ihtiyacımız yoktur. Daha iyi bir görünürlük elde etmek için, belirli alanları tutmak üzere anonim değişkenler oluşturabilirsiniz.
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 // anonim ve kullanılmayanlar _ olarak işaretlenir
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) // sysinfo sistem çağrısı başarısız oldu:
32 return
33 }
34
35 fmt.Printf("Memory: total=%d MB free=%d MB buffer=%d MB\n", // Bellek: toplam=%d MB boş=%d MB arabellek=%d MB
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", // Takas: toplam=%d MB boş=%d MB
40 info.Totalswap*uint64(info.MemUnit)/1024/1024,
41 info.Freeswap*uint64(info.MemUnit)/1024/1024)
42}
Sonuç olarak, değişkenler etiketlenmeden okunur. Anonim değerler aslında bir yapıya depolansa da, kod üzerinde etiket/okunabilir işaret yoktur.
Sonuç
- Go'nun
syscallveunsafekullanımı hala C/CGo'dan daha güvenlidir - Kolayca genişletilebilecek büyük bir proje yazıyorsanız:
- Anonim değişkenler oluşturmayın; üyeler için her bir ismi oluşturun.
- Sınırlı kullanıma sahip bir proje yazıyorsanız:
- Kullanılmayan alanları tutmak için anonim değişkenleri kullanabilirsiniz.
- Go'nun
syscalldüşük seviyeli çağrıları ele almak için güçlü ve moderndir