Go語言共享內(nèi)存讀寫實(shí)例分析
本文實(shí)例分析了Go語言共享內(nèi)存讀寫的方法。分享給大家供大家參考。具體分析如下:
前面分析了Go語言指針運(yùn)算和內(nèi)嵌C代碼的方法,做了一個Go語言共享內(nèi)存讀寫的實(shí)驗(yàn)。
先大概說下什么是共享內(nèi)存。我們知道不同進(jìn)程見的內(nèi)存是互相獨(dú)立的,沒辦法直接互相操作對方內(nèi)的數(shù)據(jù),而共享內(nèi)存則是靠操作系統(tǒng)提供的內(nèi)存映射機(jī)制,讓不同進(jìn)程的一塊地址空間映射到同一個虛擬內(nèi)存區(qū)域上,使不同的進(jìn)程可以操作到一塊共用的內(nèi)存塊。共享內(nèi)存是效率最高的進(jìn)程間通訊機(jī)制,因?yàn)閿?shù)據(jù)不需要在內(nèi)核和程序之間復(fù)制。
共享內(nèi)存用到的是系統(tǒng)提供的mmap函數(shù),它可以將一個文件映射到虛擬內(nèi)存的一個區(qū)域中,程序使用指針引用這個區(qū)域,對這個內(nèi)存區(qū)域的操作會被回寫到文件上,Go內(nèi)置的syscall包中有mmap函數(shù),但是它是經(jīng)過封裝的,返回的是[]byte,沒辦法做我需求的指針運(yùn)算,所以我還是用cgo來調(diào)用原生的mmap。
實(shí)驗(yàn)分為讀和寫兩個程序,這樣我們可以觀察到讀進(jìn)程可以讀到寫進(jìn)程寫入共享內(nèi)存的信息。
下面是shm_writer.go的代碼:
/*
#cgo linux LDFLAGS: -lrt
#include <fcntl.h>
#include <unistd.h>
#include <sys/mman.h>
#define FILE_MODE (S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH)
int my_shm_new(char *name) {
shm_unlink(name);
return shm_open(name, O_RDWR|O_CREAT|O_EXCL, FILE_MODE);
}
*/
import "C"
import (
"fmt"
"unsafe"
)
const SHM_NAME = "my_shm"
const SHM_SIZE = 4 * 1000 * 1000 * 1000
type MyData struct {
Col1 int
Col2 int
Col3 int
}
func main() {
fd, err := C.my_shm_new(C.CString(SHM_NAME))
if err != nil {
fmt.Println(err)
return
}
C.ftruncate(fd, SHM_SIZE)
ptr, err := C.mmap(nil, SHM_SIZE, C.PROT_READ|C.PROT_WRITE, C.MAP_SHARED, fd, 0)
if err != nil {
fmt.Println(err)
return
}
C.close(fd)
data := (*MyData)(unsafe.Pointer(ptr))
data.Col1 = 100
data.Col2 = 876
data.Col3 = 8021
}
下面是shm_reader.go的代碼:
/*
#cgo linux LDFLAGS: -lrt
#include <fcntl.h>
#include <unistd.h>
#include <sys/mman.h>
#define FILE_MODE (S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH)
int my_shm_open(char *name) {
return shm_open(name, O_RDWR);
}
*/
import "C"
import (
"fmt"
"unsafe"
)
const SHM_NAME = "my_shm"
const SHM_SIZE = 4 * 1000 * 1000 * 1000
type MyData struct {
Col1 int
Col2 int
Col3 int
}
func main() {
fd, err := C.my_shm_open(C.CString(SHM_NAME))
if err != nil {
fmt.Println(err)
return
}
ptr, err := C.mmap(nil, SHM_SIZE, C.PROT_READ|C.PROT_WRITE, C.MAP_SHARED, fd, 0)
if err != nil {
fmt.Println(err)
return
}
C.close(fd)
data := (*MyData)(unsafe.Pointer(ptr))
fmt.Println(data)
}
上面的程序映射了一塊4G的虛擬內(nèi)存,用來證明mmap沒有實(shí)際占用4G內(nèi)存,而是用到了虛擬內(nèi)存。
shm_writer創(chuàng)建好共享內(nèi)存以后,往內(nèi)存區(qū)域?qū)懭肓艘粋€結(jié)構(gòu)體,shm_reader則讀出一個結(jié)構(gòu)體。
內(nèi)嵌的C代碼中有一行 :
因?yàn)閙map在Mac上不需要連接librt,在linux上則需要,所以做了一個條件鏈接,這是cgo提供的功能。
上面代碼中還用到一個cgo的技巧,像shm_open和mmap函數(shù)在錯誤時會返回errno,如果我們在go中使用多返回值語法,cgo會自己把錯誤碼轉(zhuǎn)換成錯誤信息,很方便的功能。
希望本文所述對大家的Go語言程序設(shè)計有所幫助。
相關(guān)文章
從錯誤中學(xué)習(xí)改正Go語言六個壞習(xí)慣提高編程技巧
這篇文章主要為大家介紹了從錯誤中學(xué)習(xí)改正Go語言五個壞習(xí)慣提高編程技巧示例詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2023-05-05go中實(shí)現(xiàn)字符切片和字符串互轉(zhuǎn)
這篇文章主要為大家詳細(xì)介紹了go語言中如何實(shí)現(xiàn)字符切片和字符串互轉(zhuǎn),文中的示例代碼講解詳細(xì),具有一定的學(xué)習(xí)價值,感興趣的小伙伴可以了解一下2023-11-11golang中struct和[]byte的相互轉(zhuǎn)換示例
這篇文章主要介紹了golang中struct和[]byte的相互轉(zhuǎn)換示例,小編覺得挺不錯的,現(xiàn)在分享給大家,也給大家做個參考。一起跟隨小編過來看看吧2018-07-07go-micro使用Consul做服務(wù)發(fā)現(xiàn)的方法和原理解析
這篇文章主要介紹了go-micro使用Consul做服務(wù)發(fā)現(xiàn)的方法和原理,這里提供一個通過docker快速安裝Consul的方式,當(dāng)然前提是你得安裝了docker,需要的朋友可以參考下2022-04-04