Go語言共用記憶體讀寫執行個體分析_Golang

來源:互聯網
上載者:User

本文執行個體分析了Go語言共用記憶體讀寫的方法。分享給大家供大家參考。具體分析如下:

前面分析了Go語言指標運算和內嵌C代碼的方法,做了一個Go語言共用記憶體讀寫的實驗。

先大概說下什麼是共用記憶體。我們知道不同進程見的記憶體是互相獨立的,沒辦法直接互相操作對方內的資料,而共用記憶體則是靠作業系統提供的記憶體映射機制,讓不同進程的一塊地址空間映射到同一個虛擬記憶體地區上,使不同的進程可以操作到一塊共用的記憶體塊。共用記憶體是效率最高的進程間通訊機制,因為資料不需要在核心和程式之間複製。

共用記憶體用到的是系統提供的mmap函數,它可以將一個檔案對應到虛擬記憶體的一個地區中,程式使用指標引用這個地區,對這個記憶體地區的操作會被回寫到檔案上,Go內建的syscall包中有mmap函數,但是它是經過封裝的,返回的是[]byte,沒辦法做我需求的指標運算,所以我還是用cgo來調用原生的mmap。

實驗分為讀和寫兩個程式,這樣我們可以觀察到讀進程可以讀到寫進程寫入共用記憶體的資訊。

下面是shm_writer.go的代碼:

複製代碼 代碼如下:
package main
/*
#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的代碼:

複製代碼 代碼如下:
package main
/*
#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的虛擬記憶體,用來證明mmap沒有實際佔用4G記憶體,而是用到了虛擬記憶體。

shm_writer建立好共用記憶體以後,往記憶體地區寫入了一個結構體,shm_reader則讀出一個結構體。

內嵌的C代碼中有一行 :

複製代碼 代碼如下:
#cgo linux LDFLAGS: -lrt

因為mmap在Mac上不需要串連librt,在linux上則需要,所以做了一個條件連結,這是cgo提供的功能。

上面代碼中還用到一個cgo的技巧,像shm_open和mmap函數在錯誤時會返回errno,如果我們在go中使用多傳回值文法,cgo會自己把錯誤碼轉換成錯誤資訊,很方便的功能。

希望本文所述對大家的Go語言程式設計有所協助。

相關文章

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.