希赛考试网
首页 > 软考 > 网络工程师

golang 进程间通信

希赛网 2024-06-25 11:26:52

在多进程系统中,进程间通信是必不可少的。在 Golang 中,通过 channel、共享内存、管道和信号等方式进行进程间通信。

一、channel

channel 是 Golang 中的一种数据类型,可用于协程之间的通信。channel 可以将数据从一个协程中传递到另一个协程中。

在使用 channel 时,需要定义 channel 的类型(如 chan int),并通过 make 函数创建一个 channel 对象。使用 channel 的时候,可以通过 <- 和 -> 进行读写操作。

例如:

```

ch := make(chan int)

go func() {

ch <- 1

}()

i := <- ch

```

通过 make 函数创建了一个类型为 int 的 channel 对象。在一个协程中向 channel 中写入了 1,在另一个协程中从 channel 中读取了数据。需要注意的是,当一个协程试图从一个没有数据的 channel 中读取数据时,该协程会阻塞。

channel 还有一个重要的特性就是可以进行关闭操作。当一个 channel 被关闭后,读取方会不断的读取已经存在的数据,直到 channel 中的数据被全部读取完为止。

```

ch := make(chan int)

go func() {

for i := 0; i < 5; i++ {

ch <- i

}

close(ch)

}()

for i := range ch {

fmt.Println(i)

}

```

通过这段代码,我们可以看到,虽然在协程中写入了 5 次数据,但在读取过程中只输出了 0 到 4 个数字。

二、共享内存

共享内存是指多个进程可以通过共享一块内存区域进行数据交换。在 Golang 中,可以通过 sync 包中的 Mutex 和 RWmutex 类型来实现共享内存。

Mutex 是一种排他锁,用于在多个进程之间协调对共享资源的访问。例如:

```

var mu sync.Mutex

var count int

func main() {

for i := 0; i < 10; i++ {

go func() {

mu.Lock()

defer mu.Unlock()

count++

}()

}

time.Sleep(time.Second)

fmt.Println(count)

}

```

在这段代码中,我们通过互斥锁来协调对 count 变量的访问,保证多个协程同时修改 count 变量的时候,能够正确的得到最终的结果。

而 RWmutex 则是用于读写分离的场景,主要用于在读多写少的情况下提高性能。例如:

```

var mu sync.RWMutex

var m = make(map[string]int)

func main() {

for i := 0; i < 10; i++ {

go func() {

mu.RLock()

defer mu.RUnlock()

fmt.Println(m)

}()

}

for i := 0; i < 10; i++ {

go func() {

mu.Lock()

defer mu.Unlock()

m["count"]++

}()

}

time.Sleep(time.Second)

fmt.Println(m)

}

```

在这段代码中,我们通过读写互斥锁保证多个协程同时读取和写入一个 map 变量时能够正确的得到最终的结果。

三、管道

管道是一种单向的、阻塞式的流,可以在两个进程之间传递数据。在 Golang 中,通过 os/exec 包中的 Command 方法和 io 包中的 Pipe 方法可以创建管道。

例如:

```

cmd1 := exec.Command("ls", "-lh")

cmd2 := exec.Command("grep", "test")

stdout1, _ := cmd1.StdoutPipe()

stdout2, _ := cmd2.StdoutPipe()

cmd1.Start()

cmd2.Start()

go func() {

defer func() {

stdout1.Close()

stdout2.Close()

}()

for {

b := make([]byte, 1024)

n, err := stdout1.Read(b)

if err == io.EOF {

break

}

stdout2.Write(b[:n])

}

}()

cmd1.Wait()

cmd2.Wait()

```

在这段代码中,我们通过创建两个进程 cmd1 和 cmd2,并在这两个进程之间通过管道进行数据传递。

四、信号

信号是一种异步通信机制,用于对多个进程进行通信和同步。在 Golang 中,可以通过 os 包中的 Signal 方法来捕捉和处理信号。

例如:

```

func main() {

sigs := make(chan os.Signal, 1)

signal.Notify(sigs, syscall.SIGINT, syscall.SIGTERM)

go func() {

sig := <-sigs

fmt.Println(sig)

os.Exit(0)

}()

fmt.Println("awaiting signal")

<-time.After(30 * time.Second)

}

```

在这段代码中,我们创建了一个 channel 用于接收信号,并通过 Notify 方法监听了 SIGINT 和 SIGTERM 两类信号。当程序接收到一个信号时,会通过协程执行指定的操作。

扫码咨询 领取资料


软考.png


网络工程师 资料下载
备考资料包大放送!涵盖报考指南、考情深度解析、知识点全面梳理、思维导图等,免费领取,助你备考无忧!
立即下载
网络工程师 历年真题
汇聚经典真题,展现考试脉络。精准覆盖考点,助您深入备考。细致解析,助您查漏补缺。
立即做题

软考资格查询系统

扫一扫,自助查询报考条件