美文网首页
go并发编程 - 待完善

go并发编程 - 待完善

作者: 如逆水行舟不进则退 | 来源:发表于2020-08-25 10:14 被阅读0次
    
    package main
    
    import (
      "fmt"
      "time"
    )
    
    func main() {
      //fmt.Println("Hello World")
      go printNum()
      go printLetter()
      time.Sleep(3 * time.Second)
      fmt.Println("\n main over ... ")
    }
    
    func printNum() {
      for i:=1;i<=5;i++ {
        time.Sleep(250 * time.Millisecond)
        fmt.Printf("%d", i)
      }
    }
    
    func printLetter() {
      for i:='a';i<='e';i++ {
        time.Sleep(400 * time.Millisecond)
        fmt.Printf("%c", i)
      }
    }
    
    • 定义channel
    package main
    
    func main() {
      //fmt.Println("Hello World")
      var ch0 chan string
      ch1 := make(chan string)
      ch2 := make(chan interface{})
      type Equip struct {}
      ch3 := make(chan *Equip)
    }
    
    
    • 循环接收channel 数据
    package main
    
    import "fmt"
    
    func main() {
      //fmt.Println("Hello World")
      ch1 := make(chan string)
      go sendData(ch1)
      // 1.循环接受数据方式1
      //for {
      //  data := <-ch1
      //  if data == "" {
      //    break
      //  }
      //  fmt.Println("从通道数据中读取数据方式1:", data)
      //}
    
      // 2.循环接受数据方式2
      //for {
      //  data, ok := <- ch1
      //  fmt.Println(ok)
      //  if !ok {
      //    break
      //  }
      //  fmt.Println("从通道数据中读取数据方式2:", data)
      //}
    
      // 3.循环接收数据方式3
      // for ... range 循环会自动判断通道是否关闭,自动break循环
      for value := range ch1 {
        fmt.Println("从通道数据中读取数据方式3:", value)
      }
    
    }
    
    func sendData(ch1 chan string) {
      defer close(ch1)
      for i := 0; i < 3; i++ {
        ch1 <- fmt.Sprintf("发送数据 %d\n", i)
      }
      fmt.Println("发送数据完毕。。")
      // 显式调用close() 实现关闭通道
    }
    
    
    • channel 阻塞
    package main
    
    import (
      "fmt"
      "time"
    )
    
    func main() {
      //fmt.Println("Hello World")
      var ch1 chan int
      ch1 = make(chan int)
      fmt.Printf("%T \n", ch1)
      ch2 := make(chan bool)
      go func() {
        data, ok := <-ch1
        if ok {
          fmt.Println("子goroutine 取到数值:", data)
        }
        time.Sleep(1 * time.Second)
        fmt.Println("子goroutine over ...")
        ch2 <- true
      }()
      ch1 <- 10
      <-ch2 // 阻塞
      fmt.Println("main over ...")
    }
    
    
    
    • 关闭channel
    package main
    
    import "fmt"
    
    func main() {
      //fmt.Println("Hello World")
      var ch1 chan int
      ch1 = make(chan int)
      go func() {
        ch1 <- 100
        ch1 <- 100
        close(ch1)
        //ch1 <- 10 // 关闭channel, 无法写入数据
      }()
      data, ok := <-ch1
      fmt.Println("main 读取数据:", data, ok)
      data, ok = <-ch1
      fmt.Println("main 读取数据:", data, ok)
      data, ok = <-ch1
      fmt.Println("main 读取数据:", data, ok)
      data, ok = <-ch1
      fmt.Println("main 读取数据:", data, ok)
      data, ok = <-ch1
      fmt.Println("main 读取数据:", data, ok)
    }
    
    输出:
    main 读取数据: 100 true
    main 读取数据: 100 true
    main 读取数据: 0 false
    main 读取数据: 0 false
    main 读取数据: 0 false
    
    
    • 缓冲channel
    package main
    
    import (
      "fmt"
      "time"
    )
    
    func main() {
      //fmt.Println("Hello World")
      //1.非缓冲通道
      ch1 := make(chan int)
      fmt.Println("非缓冲通道", len(ch1), cap(ch1))
      go func() {
       data := <- ch1
       fmt.Println("获得数据", data)
      }()
      ch1 <- 100
      time.Sleep(time.Second)
      fmt.Println("赋值ok","main over...")
    
      //2.非缓冲通道
      ch2 := make(chan string)
      go sendData(ch2)
      time.Sleep(time.Second)
      for data := range ch2 {
        time.Sleep(time.Second)
        fmt.Println("\t 读取数据:", data)
      }
      fmt.Println("main over ...")
    
      // 缓冲通道,缓冲区满了才会阻塞
      ch3 := make(chan string, 6)
      go sendData(ch3)
      for data := range ch3 {
       fmt.Println("\t 读取数据:", data)
      }
      fmt.Println("main over")
    }
    
    func sendData(ch chan string) {
      for i := 1; i <=3; i++ {
        ch <- fmt.Sprintf("data %d", i)
        fmt.Println("往通道放入数据:", i)
      }
      defer close(ch)
    }
    
    
    package main
    
    import (
      "fmt"
      "math/rand"
      "strings"
      "time"
    )
    
    func main() {
      //fmt.Println("Hello World")
      // 用channel来传递数据,不再需要自己去加锁维护一个全局的阻塞队列
      ch1 := make(chan int)
      ch_bool1 := make(chan bool) // 判断结束
      ch_bool2 := make(chan bool) // 判断结束
      ch_bool3 := make(chan bool) // 判断结束
    
      rand.Seed(time.Now().UnixNano())
    
      // 生产者
      go producer(ch1)
      // 消费者
      go consumer(1, ch1, ch_bool1)
      go consumer(2, ch1, ch_bool2)
      go consumer(3, ch1, ch_bool3)
    
      <-ch_bool1
      <-ch_bool2
      <-ch_bool3
    
      defer fmt.Println("main...over...")
    
      fmt.Println("main over")
    }
    
    func producer(ch1 chan int) {
      for i := 1; i <= 10; i++ {
        ch1 <- i
        fmt.Println("生产蛋糕,编号:", i)
        time.Sleep(time.Duration(rand.Intn(500)) * time.Millisecond)
      }
      defer close(ch1)
    }
    
    func consumer(num int, ch1 chan int, ch chan bool) {
      for data := range ch1 {
        pre := strings.Repeat("——————", num)
        fmt.Printf("%s %d 号购买 %d号蛋糕 \n", pre, num, data)
        time.Sleep(time.Duration(rand.Intn(500)) * time.Millisecond)
      }
      ch <- true
      defer close(ch)
    }
    
    
    
    
    • 单向channel
    package main
    
    import (
      "fmt"
      "time"
    )
    
    func main() {
      // 双向通道
      ch1 := make(chan string)
      go fun1(ch1)
    
      data := <-ch1
    
      fmt.Println("main,接受到数据:", data)
      ch1 <- "Go语言好学吗?"
      ch1 <- "Go语言好学吗???"
      go fun2(ch1)
      go fun3(ch1)
      time.Sleep(time.Second)
    
      fmt.Println("main over")
    }
    
    func fun1(ch1 chan string) {
      ch1 <- "我是Steven老师"
      data := <-ch1
      data2 := <-ch1
      fmt.Println("回应:", data, data2)
    }
    
    // 功能:只有写入数据
    func fun2(ch1 chan<- string) {
      // 只能写入
      ch1 <- "How are you?"
    }
    
    func fun3(ch1 <-chan string) {
      data := <-ch1
      fmt.Println("只读:", data)
    }
    
    
    
    • NewTimer()函数
    package main
    
    import (
      "fmt"
      "time"
    )
    
    func main() {
    
      // 创建计时器
      timer1 := time.NewTimer(5 * time.Second)
      // fmt.Printf("%T \n", timer1)
      fmt.Println(time.Now())
      data := <- timer1.C // <-chan time.Time
      fmt.Printf("%T \n", timer1.C)
      fmt.Printf("%T \n", data)
      fmt.Println(data)
    }
    
    • After()函数
    package main
    
    import (
      "fmt"
      "time"
    )
    
    func main() {
    
      // 2.使用After(), 返回值 <-chan Time , 同Timer.C
      ch1 := time.After(5 * time.Second)
      fmt.Println(time.Now())
      data := <-ch1
      fmt.Printf("%T \n", data)
      fmt.Println(data)
    }
    
    • select 随机挑选case
    package main
    
    import (
      "fmt"
    )
    
    func main() {
    
      ch1 := make(chan int)
      ch2 := make(chan int)
      go func() {
        ch1 <- 100
      }()
    
      go func() {
        ch2 <- 200
      }()
    
      // time.Sleep(time.Second)
      select {
      case data := <-ch1:
          fmt.Println("ch1中读取数据了:", data)
      case data := <-ch2:
          fmt.Println("ch2中读取数据了:", data)
      default:
          fmt.Println("执行了default...")
      }
    }
    
    
    
    • 观察select的阻塞机制
    package main
    
    import (
      "fmt"
      "time"
    )
    
    func main() {
    
      ch1 := make(chan int)
      ch2 := make(chan int)
    
      go func() {
        time.Sleep(10 * time.Millisecond)
        data := <-ch1
        fmt.Println("ch1:", data)
      }()
    
      go func() {
        time.Sleep(2 * time.Second)
        data := <-ch2
        fmt.Println("ch2:", data)
      }()
    
      select {
      case ch1 <- 100 :// 阻塞
          close(ch1)
          fmt.Println("ch1 中写入数据")
      case ch2 <- 200: // 阻塞
          close(ch2)
          fmt.Println("ch2 中写入数据")
      case <-time.After(2 * time.Millisecond) : // 阻塞
          fmt.Println("执行延时通道")
      //default:
      //  fmt.Println("default...")
      }
    
      time.Sleep( 4 * time.Second)
      fmt.Printf("main over")
    }
    
    
    
    • 同步等待组
    package main
    
    import (
      "fmt"
      "math/rand"
      "strings"
      "sync"
      "time"
    )
    
    func main() {
      var wg sync.WaitGroup
      fmt.Printf("%T \n", wg) // sync.WaitGroup
      fmt.Println(wg)
      wg.Add(3)
      rand.Seed(time.Now().UnixNano())
    
      go printNum(&wg, 1)
      go printNum(&wg, 2)
      go printNum(&wg, 3)
    
      wg.Wait() // 进入阻塞状态,当计数为0时解除阻塞
      defer fmt.Println("main over ...")
    
    }
    
    func printNum(wg *sync.WaitGroup, num int) {
      for i := 1; i <=3; i++ {
        // 在每个Goroutine 前面添加多个制表符方便观看打印结果
        pre := strings.Repeat("\t", num-1)
        fmt.Printf("%s 第 %d号子goroutine, %d \n", pre, num, i)
        time.Sleep(time.Second)
      }
      wg.Done() // 计数器减1
    }
    
    
    • 互斥锁
    package main
    
    import (
      "fmt"
      "strconv"
      "strings"
      "sync"
      "time"
    )
    var tickets int = 20
    var wg sync.WaitGroup
    var mutex sync.Mutex
    
    func main() {
      wg.Add(4)
      go saleTickets("1号窗口", &wg)
      go saleTickets("2号窗口", &wg)
      go saleTickets("3号窗口", &wg)
      go saleTickets("4号窗口", &wg)
      wg.Wait()
      defer fmt.Println("所有车票都售空")
    }
    
    func saleTickets(name string, wg *sync.WaitGroup) {
      defer wg.Done()
      for {
        // 锁定
        mutex.Lock()
        if tickets > 0 {
          time.Sleep(1 * time.Second)
          // 获取窗口的编号
          num, _ := strconv.Atoi(name[:1])
          pre := strings.Repeat("------", num)
          fmt.Println(pre, name, tickets)
          tickets--
        } else {
          fmt.Printf("%s 结束售票 \n", name)
          mutex.Unlock()
          break
        }
        // 解锁
        mutex.Unlock()
      }
    }
    
    
    

    相关文章

      网友评论

          本文标题:go并发编程 - 待完善

          本文链接:https://www.haomeiwen.com/subject/isnnjktx.html