910 words
5 minutes
Go语言教程:并发与互斥锁
本文将通过一个示例代码,详细讲解Go语言中的并发编程和互斥锁的使用。示例代码展示了如何使用goroutine进行并发操作,以及如何使用互斥锁保护共享资源。
示例代码解析
导入包
首先,我们需要导入一些必要的包:
import ( "bytes" "flag" "fmt" "io" "io/ioutil" "log" "sync")bytes:提供了缓冲区操作。flag:用于解析命令行参数。fmt:格式化I/O。io:基本的I/O接口。ioutil:I/O工具函数。log:日志记录。sync:并发原语,包括互斥锁。
全局变量
var protecting uintprotecting变量用于指示是否使用互斥锁来保护数据写入。值为0表示不使用,值大于0表示使用。
初始化函数
func init() { flag.UintVar(&protecting, "protecting", 1, "It indicates whether to use a mutex to protect data writing.")}init函数用于初始化命令行参数protecting,默认值为1。
主函数
func main() { flag.Parse() var buffer bytes.Buffer
const ( max1 = 5 // 启用的goroutine数量 max2 = 10 // 每个goroutine写入的数据块数量 max3 = 10 // 每个数据块中重复的数字数量 )
var mu sync.Mutex sign := make(chan struct{}, max1)
for i := 1; i <= max1; i++ { go func(id int, writer io.Writer) { defer func() { sign <- struct{}{} }() for j := 1; j <= max2; j++ { header := fmt.Sprintf("\\n[id: %d, iteration: %d]", id, j) data := fmt.Sprintf(" %d", id*j) if protecting > 0 { mu.Lock() } _, err := writer.Write([]byte(header)) if err != nil { log.Printf("error: %s [%d]", err, id) } for k := 0; k < max3; k++ { _, err := writer.Write([]byte(data)) if err != nil { log.Printf("error: %s [%d]", err, id) } } if protecting > 0 { mu.Unlock() } } }(i, &buffer) }
for i := 0; i < max1; i++ { <-sign } data, err := ioutil.ReadAll(&buffer) if err != nil { log.Fatalf("fatal error: %s", err) } log.Printf("The contents:\\n%s", data)}代码详解
-
解析命令行参数:
flag.Parse() -
定义缓冲区:
var buffer bytes.Buffer -
常量定义:
const (max1 = 5 // 启用的goroutine数量max2 = 10 // 每个goroutine写入的数据块数量max3 = 10 // 每个数据块中重复的数字数量) -
互斥锁和信号通道:
var mu sync.Mutexsign := make(chan struct{}, max1) -
启动goroutine:
for i := 1; i <= max1; i++ {go func(id int, writer io.Writer) {defer func() {sign <- struct{}{}}()for j := 1; j <= max2; j++ {header := fmt.Sprintf("\\n[id: %d, iteration: %d]", id, j)data := fmt.Sprintf(" %d", id*j)if protecting > 0 {mu.Lock()}_, err := writer.Write([]byte(header))if err != nil {log.Printf("error: %s [%d]", err, id)}for k := 0; k < max3; k++ {_, err := writer.Write([]byte(data))if err != nil {log.Printf("error: %s [%d]", err, id)}}if protecting > 0 {mu.Unlock()}}}(i, &buffer)} -
等待所有goroutine完成:
for i := 0; i < max1; i++ {<-sign} -
读取并打印缓冲区内容:
data, err := ioutil.ReadAll(&buffer)if err != nil {log.Fatalf("fatal error: %s", err)}log.Printf("The contents:\\n%s", data)
互斥锁的作用
在并发编程中,多个goroutine可能会同时访问共享资源,导致数据竞争。互斥锁(sync.Mutex)用于确保同一时间只有一个goroutine可以访问共享资源,从而避免数据竞争。
在本示例中,如果protecting大于0,则会使用互斥锁保护数据写入操作:
if protecting > 0 { mu.Lock()}_, err := writer.Write([]byte(header))if err != nil { log.Printf("error: %s [%d]", err, id)}for k := 0; k < max3; k++ { _, err := writer.Write([]byte(data)) if err != nil { log.Printf("error: %s [%d]", err, id) }}if protecting > 0 { mu.Unlock()}举一反三
通过本示例,我们可以举一反三,理解并应用以下概念:
- 并发编程:使用goroutine实现并发操作。
- 互斥锁:使用
sync.Mutex保护共享资源,避免数据竞争。 - 信号通道:使用通道(
chan)实现goroutine间的同步。
希望通过本教程,您能更好地理解Go语言中的并发编程和互斥锁的使用。祝您编程愉快!
Share
If this article helped you, please share it with others!
Last updated on 2022-05-23,1327 days ago
Some content may be outdated