golang channel

ex1

package main
/*
goroutine 是由GO运行时管理的轻量级线程
go f(x,y, z) 就启动了一个goroutine, 其中f,x,y,z在当前goroutine中立即计算, f内容的执行在另一个新goroutine中。
所有的goroutine都是运行在同一个地址空间中, 所有访问共享内存时,必须进行同步处理。
在sync包中上, 提供了同步需要的原语
*/
import (
    "fmt"
    "time"
)

func say(s string) {
    for i := 0; i < 5; i++ {
        time.Sleep(100 * time.Millisecond)
        fmt.Println(s)
    }
}

func main() {
    go say("world")
    say("hello")
}

ex2

package main


/*
Channels 就管道,就是剧导管, 你可能管道操作符进行读写, 操作符为 <-
ch <- v    // 把 v 写入管道
v := <-ch  // 从 ch 管道中读出到 v 变量中
数据的流向, 就箭头的指向。
所有 maps , slices, channels 复杂结构都需要通过make来创建
ch := make (chan int)
默认情况下, 发收都需要对端准备好了才行, 这样的前提使得goroutine同步就不需要显式的锁处理,降低了复杂度,简化的设计。

下面示例代码, 对slice的值求和。 分布式的工作在两个goroutine中。当其两个完成计算时,最终结果也计算出来了
*/

import "fmt"

func sum(s []int, c chan int) {
    sum := 0
    for _, v := range s {
        sum += v
    }
    c <- sum // send sum to c
}

func main() {
    s := []int{7, 2, 8, -9, 4, 0}

    c := make(chan int)
    go sum(s[:len(s)/2], c)
    go sum(s[len(s)/2:], c)
    x, y := <-c, <-c // receive from c

    fmt.Println(x, y, x+y)
}

ex3

/*
Channels 就管道
导管通过第二个参数,是可以指定其缓存长度的
ch := make(chan int, 100)
当管道满时, 发送会阻塞
当管道空时, 接收会阻塞

修改下面的代码,可以进行测试一下
*/

package main

import (
    "fmt"
    "time"
)

// 例1、写阻塞等待
func put_chan(ch chan int, n int)  {
    for i := 0 ; i < n;  i++{
        fmt.Println("put: ", i, time.Now().UTC())
        ch <- i
    }
    close(ch)
}

func read_chan(ch chan int, quit chan int)  {
    for c := range ch{
        time.Sleep(time.Duration(time.Second * 3))
        fmt.Println(c, time.Now().UTC())
    }
    time.Sleep(time.Duration(time.Second * 3))
    quit <- 1
}
func main() {
    ch := make(chan int, 2)
    quit := make(chan int)
    go put_chan(ch, 10)
    go read_chan(ch, quit)


    fmt.Println("end", <- quit, time.Now().UTC())

}

 例2、读阻塞等待
//func put_chan(ch chan int, n int)  {
//  for i := 0 ; i < n;  i++{
//      time.Sleep(time.Duration(time.Second * 3))
//      ch <- i
//  }
//  time.Sleep(time.Duration(time.Second * 3))
//  close(ch)
//}
//
//func read_chan(ch chan int, quit chan int)  {
//  for c := range ch{
//      fmt.Println(c, time.Now())
//  }
//  quit <- 1
//}
//func main() {
//  ch := make(chan int, 2)
//  quit := make(chan int)
//  go put_chan(ch, 2)
//  go read_chan(ch, quit)
//
//
//  fmt.Println("end", <- quit, time.Now())
//
//}

// 例3、测试中发现,系统检测会出现死锁
//func main() {
//  ch := make(chan int, 2)
//  ch <- 1
//  ch <- 2
//  fmt.Println(<-ch)
//  fmt.Println(<-ch)
//  fmt.Println(<-ch)
//  fmt.Println("end")
//
//}

ex4

/*
Channels Range & Close 范围排列与关闭
发送者可以通过关闭通道来通知没有更多数据需要发送了。
接收者可以检测通道是否已经关闭了,通过指定第二个参数来实现,具体如下
v , ok := <- ch
当ok为false, 则通道已经关闭,没有数据了。
或者可以使用循环 for i := range c 来取数据,至到通道关闭。
注意<惯例>:
   1. 应该只让发送者来关闭通道。 绝对不要让接收者来关闭。 在一个已经关闭了的通道上发数据会引发panic
   2. 通道,只在最终不要了, 需要终止的时候才来关闭之
*/

package main

import (
    "fmt"
)

func fibonacci(n int, c chan int) {
    x, y := 0, 1
    for i := 0; i < n; i++ {
        c <- x
        x, y = y, x+y
    }
    close(c)
}

func main() {
    c := make(chan int, 10)
    go fibonacci(cap(c), c)
    for i := range c {
        fmt.Println(i)
    }
}

ex5

/*
Channels  select  选择查询操作
选择查询语句, 让当前goroutine 等待多个通讯操作
当没有条件满足时, select阻塞
当有  条件满足时, select执行
当有多条件满足时, select随机执行满足条件之一
*/

package main

import "fmt"

func fibonacci(c, quit chan int) {
    x, y := 0, 1
    for {
        select {
        case c <- x:    // 写
            x, y = y, x+y
        case <-quit:    // 读
            fmt.Println("quit")
            return
        }
    }
}

func main() {
    c := make(chan int)
    quit := make(chan int)
    go func() {
        for i := 0; i < 10; i++ {
            fmt.Println(<-c)
        }
        quit <- 0
    }()
    fibonacci(c, quit)
}

ex6

/*
Channels  select  选择查询操作
缺省选择, 当没有case条件满足时, 直接选择默认条件
*/

package main

import (
    "fmt"
    "time"
)

func main() {
    tick := time.Tick(100 * time.Millisecond)
    boom := time.After(500 * time.Millisecond)
    for {
        select {
        case <-tick:
            fmt.Println("tick.")
        case <-boom:
            fmt.Println("BOOM!")
            return
        default:
            fmt.Println("    .")
            time.Sleep(50 * time.Millisecond)
        }
    }
}

转载于:https://www.cnblogs.com/freebird92/p/10518422.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
在 Go 中,可以使用 channel 实现限流,即通过 channel 的容量控制并发执行的协程数。 示例代码如下: ```go package main import ( "fmt" "time" ) func worker(id int, jobs <-chan int, results chan<- int) { for j := range jobs { fmt.Printf("worker %d 执行任务 %d\n", id, j) time.Sleep(time.Second) // 模拟任务执行时间 results <- j * 2 } } func main() { jobs := make(chan int, 100) // 创建任务 channel,缓冲区大小为 100 results := make(chan int, 100) // 创建结果 channel,缓冲区大小为 100 // 创建 3 个 worker 协程,即最多同时执行 3 个任务 for w := 1; w <= 3; w++ { go worker(w, jobs, results) } // 发送 9 个任务到 jobs channel for j := 1; j <= 9; j++ { jobs <- j } close(jobs) // 关闭 jobs channel,表示所有任务已发送完毕 // 收集所有结果 for a := 1; a <= 9; a++ { <-results } } ``` 在上面的示例中,我们创建了一个 `jobs` channel 和一个 `results` channel,用于分别传递任务和结果。我们创建了 3 个 worker 协程,并将 `jobs` 和 `results` channel 分别传递给它们。在主协程中,我们向 `jobs` channel 发送 9 个任务,并关闭 `jobs` channel,表示所有任务已发送完毕。然后我们收集所有结果。 由于 `jobs` channel 的缓冲区大小为 100,即最多可以存储 100 个任务,而 `results` channel 的缓冲区也为 100,即最多可以存储 100 个结果。因此,当 worker 协程数小于等于 3 时,所有任务都可以立即执行;当 worker 协程数大于 3 时,多余的任务会被存储在 `jobs` channel 中,直到有空闲的 worker 协程可以执行它们。这样就实现了限流的功能。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值