channel并发场景应用案例

计算并发

  1. 计算并发这是一个简单的计算并发案例,其中使用了通道和 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 函数将数据写入两个通道 ch1ch2。在 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 函数从 ch1ch2 通道中读取数据。在 main 函数中,使用 select 语句向两个通道中写入数据,select 语句会阻塞直到其中一个通道可写,然后将数据写入该通道。最后,使用 close 函数关闭两个通道,以便 consumer 函数能够及时停止。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值