计算并发
计算并发这是一个简单的计算并发案例,其中使用了通道和 Go 协程来并行计算。
package main
import (
"fmt"
)
func worker(id int, jobs <-chanint, results chan<- int) {
for j := range jobs {
fmt.Printf("worker %d started job %d\n", id, j)
results <- j * 2
fmt.Printf("worker %d finished job %d\n", id, j)
}
}
func main() {
numJobs := 10
jobs := make(chanint, numJobs)
results := make(chanint, numJobs)
for w := 1; w <= 3; w++ {
go worker(w, jobs, results)
}
for j := 1; j <= numJobs; j++ {
jobs <- j
}
close(jobs)
for r := 1; r <= numJobs; r++ {
<-results
}
}
这里定义了一个 worker 函数,它接受两个通道参数:一个是用于接收工作任务的 jobs 通道,一个是用于发送工作结果的 results 通道。在 worker 函数内部,它会循环读取 jobs 通道中的任务,然后并行计算,将结果写入 results 通道中。在主函数中,我们先将所有工作任务写入 jobs 通道,然后通过 for 循环读取 results 通道中的结果。
互斥锁
这是一个使用互斥锁来同步访问共享资源的案例。
package main
import (
"fmt""sync"
)
var (
counter = 0
mutex sync.Mutex
)
func worker(wg *sync.WaitGroup) {
defer wg.Done()
for i := 0; i < 100000; i++ {
mutex.Lock()
counter++
mutex.Unlock()
}
}
func main() {
var wg sync.WaitGroup
wg.Add(2)
go worker(&wg)
go worker(&wg)
wg.Wait()
fmt.Println(counter)
}
在这个案例中,我们定义了一个 counter 变量,它用于存储工作的计数器。然后我们定义了一个 worker 函数,它会通过互斥锁来同步对 counter 变量的访问。在主函数中,我们创建了两个 Go 协程来执行 worker 函数,并等待它们完成后输出最终的计数器值
生产者和消费者模型
生产者和消费者模型是一个典型的并发模型,通过使用 channel 可以很好地实现。
func producer(ch chan<- int) {
for i := 0; i < 10; i++ {
ch <- i
}
close(ch)
}
func consumer(ch <-chanint) {
for num := range ch {
fmt.Println("Consumed", num)
}
}
func main() {
ch := make(chanint)
go producer(ch)
consumer(ch)
}
在上述代码中,producer 函数将数据写入 ch 通道,而 consumer 函数从 ch 通道读取数据。close 函数用于关闭 ch 通道,以便 consumer 函数能够及时停止
多个 channel 同时读取
func producer(ch1 chan<- int, ch2 chan<- int) {
for i := 0; i < 10; i++ {
ch1 <- i
ch2 <- i * 2
}
close(ch1)
close(ch2)
}
func main() {
ch1 := make(chanint)
ch2 := make(chanint)
go producer(ch1, ch2)
for {
select {
case num1, ok := <-ch1:
if ok {
fmt.Println("Received from ch1:", num1)
} else {
fmt.Println("ch1 is closed")
}
case num2, ok := <-ch2:
if ok {
fmt.Println("Received from ch2:", num2)
} else {
fmt.Println("ch2 is closed")
}
}
}
}
在上述代码中,producer 函数将数据写入两个通道 ch1 和 ch2。在 main 函数中,使用 select 语句从两个通道中读取数据,select 语句会阻塞直到其中一个通道有数据可读,然后处理该通道的数据。
多个 channel 同时写入
func consumer(ch chanint) {
for num := range ch {
fmt.Println("Consumed", num)
}
}
func main() {
ch1 := make(chanint)
ch2 := make(chanint)
go func() {
for i := 0; i < 10; i++ {
select {
case ch1 <- i:
case ch2 <- i * 2:
}
}
close(ch1)
close(ch2)
}()
consumer(ch1)
consumer(ch2)
}
在上述代码中,consumer 函数从 ch1 和 ch2 通道中读取数据。在 main 函数中,使用 select 语句向两个通道中写入数据,select 语句会阻塞直到其中一个通道可写,然后将数据写入该通道。最后,使用 close 函数关闭两个通道,以便 consumer 函数能够及时停止。