一道map并发编程题

84 阅读2分钟

package main

import (
	"fmt"
)

func main() {
	reqCh := make(chan request)
	respCh := make(chan response)

	// 启动 10 个 goroutine 并发写入 map
	for i := 0; i < 10; i++ {
		go writeMap(reqCh, respCh)
	}

	// 启动 10 个 goroutine 并发读取 map
	for i := 0; i < 10; i++ {
		go readMap(reqCh, respCh)
	}

	// 向请求通道中发送读取和写入请求
	for i := 0; i < 20; i++ {
		if i%2 == 0 {
			reqCh <- request{operation: "write", key: fmt.Sprintf("key%d", i/2), value: i / 2}
		} else {
			reqCh <- request{operation: "read", key: fmt.Sprintf("key%d", i/2)}
		}
	}

	// 打印接收到的响应
	for i := 0; i < 20; i++ {
		resp := <-respCh
		if resp.err != nil {
			fmt.Printf("error: %v\n", resp.err)
		} else {
			fmt.Printf("key: %s, value: %d\n", resp.key, resp.value)
		}
	}
}

type request struct {
	operation string
	key       string
	value     int
}

type response struct {
	key   string
	value int
	err   error
}

func writeMap(reqCh chan request, respCh chan response) {
	m := make(map[string]int)
	for req := range reqCh {
		if req.operation == "write" {
			m[req.key] = req.value
			respCh <- response{key: req.key, value: req.value}
		} else {
			respCh <- response{key: req.key, err: fmt.Errorf("invalid operation: %s", req.operation)}
		}
	}
}

func readMap(reqCh chan request, respCh chan response) {
	m := make(map[string]int)
	for req := range reqCh {
		if req.operation == "read" {
			value, ok := m[req.key]
			if ok {
				respCh <- response{key: req.key, value: value}
			} else {
				respCh <- response{key: req.key, err: fmt.Errorf("key not found: %s", req.key)}
			}
		} else {
			respCh <- response{key: req.key, err: fmt.Errorf("invalid operation: %s", req.operation)}
		}
	}
}

这段代码展示了如何使用goroutine和通道实现并发读写一个map。

首先,我们定义了两个通道 reqCh 和 respCh,用于在读写goroutine之间传递请求和响应。

然后,我们使用两个循环分别启动了10个写入goroutine和10个读取goroutine。每个写入goroutine都会调用 writeMap 函数,而每个读取goroutine都会调用 readMap 函数。

在主函数中,我们使用一个循环向 reqCh 通道发送读取和写入请求。对于偶数次循环,我们发送一个写入请求,其中包含操作类型为 "write",键为格式化后的字符串 "key%d",值为循环索引的一半。对于奇数次循环,我们发送一个读取请求,其中包含操作类型为 "read",键为格式化后的字符串 "key%d"。

然后,我们使用另一个循环从 respCh 通道接收响应,并根据响应的类型进行处理。如果响应中的 err 字段不为空,则打印错误消息。否则,打印键和值。

writeMap 函数和 readMap 函数都是无限循环,通过 range 关键字从 reqCh 通道中接收请求。在 writeMap 函数中,我们创建了一个空的 map,然后根据请求的操作类型进行写入或错误处理,并将响应发送到 respCh 通道。在 readMap 函数中,我们也创建了一个空的 map,然后根据请求的操作类型进行读取或错误处理,并将响应发送到 respCh 通道。

总体来说,这段代码展示了如何使用goroutine和通道实现并发读写一个map,并通过请求和响应通道进行通信。通过并发读写map,可以提高程序的性能和效率。