golang实现并行
更新时间:2023-07-09golang实现并行
Go语言是一门并发支持的语言,可以通过goroutine来实现并行编程,下面会详细介绍goroutine的使用。
1. goroutine介绍
goroutine是乔治语言中的一个轻量级线程,它在Go的运行时环境中被执行。与传统的线程相比,goroutine被称为轻量级线程,因为它们的创建和销毁操作的开销很小。在Go中,可以通过关键字“go”来创建一个goroutine,并在其中执行函数。下面是一个示例:
package main import "fmt" func f(from string) { for i :=0; i < 5; i++ { fmt.Println(from, ":", i) } } func main() { // 创建并运行goroutine go f("goroutine") // 在主线程中执行函数 f("main") // 等待输入,防止程序过早退出 var input string fmt.Scanln(&input) }
在上面的示例中,我们创建了一个函数f,并在main函数中使用关键字“go”创建了一个goroutine,并在其中执行了函数f。主线程中也执行了函数f。可以看到,主线程和goroutine同时执行,输出结果会交替出现。
2. 并发安全
在并发编程中,一个很常见的问题就是竞态条件。竞态条件发生在多个goroutine竞争同一资源时。为了解决这个问题,Go提供了一个叫做mutex的互斥锁。下面是一个示例:
package main import ( "fmt" "sync" "time" ) // 共享资源 var counter int func increment(wg *sync.WaitGroup, m *sync.Mutex) { m.Lock() counter++ m.Unlock() wg.Done() } func main() { // 创建互斥锁 var mutex sync.Mutex // 创建等待组 var wg sync.WaitGroup // 启动10个goroutine增加counter的值 for i :=0; i < 10; i++ { wg.Add(1) go increment(&wg, &mutex) } // 等待所有goroutine执行完毕 wg.Wait() // 打印counter的值 fmt.Println("Counter:", counter) }
在上面的示例中,我们创建了一个互斥锁mutex,并在increment函数中使用它来保护共享资源counter。我们创建了10个goroutine来并行增加counter的值。通过使用互斥锁,我们可以保证counter的值不会被多个goroutine同时访问。
3. 通道
在Go语言中,可以使用通道(channel)来协调goroutine之间的交互。通道充当了同步器的角色,在goroutine之间传递数据并同步它们的执行。下面是一个简单的示例:
package main import ( "fmt" ) func main() { // 创建通道 ch :=make(chan int) // 启动goroutine go func() { ch <- 1 }() // 从通道中读取数据 fmt.Println(<-ch) }
在上面的示例中,我们创建了一个通道ch,并在一个匿名goroutine中将数字1发送到通道中。在main函数中,我们使用<-运算符从通道中读取数据,并将其打印到标准输出中。可以看到,通道充当了goroutine之间传递数据的媒介,并保证了它们的执行顺序。
4. 常见的并发模式
在Go语言中,有许多用于并发编程的常见模式。下面是其中的一些:
- Worker pool pattern:使用一组goroutine处理一组输入任务。
- Pipeline pattern:将输入与输出通道连接起来,形成一条管道。
- Producer-consumer pattern:使用多个goroutine来生产和消费数据。
- Pub-sub pattern:使用多个订阅者和发布者来实现消息传递。
这些模式都是由goroutine和通道构建的,可以帮助我们更好地利用并发性。