zoukankan      html  css  js  c++  java
  • 并行计算

    1、Goroutine协程:协程就是go提供的轻量级的独立运算过程,比线程还轻;创建一个协程,就是使用go关键字,后面跟上要运行的函数

    案例要求:1)、先计算1000以下所有能够被3整除的整数的和A

         2)、然后计算1000以下所有能够被5整除的整数和B

         3)、然后再计算1000以下所有能够被3和5整除的整数和C

         4)、使用A+B-C得到最后结果

    案例中,使用go关键字创建一个协程,协程函数内使用channel(chan数据,类似队列,在取chan中数据时,如果为空,会阻塞,直到chan中有数据)存储数据

    package main
    
    import (
        "fmt"
        "runtime"
        "time"
    )
    
    func get_sum_of_divisible(num int, divider int, resultChan chan int) {
        sum := 0
        for value := 0; value < num; value++ {
            if value%divider == 0 {
                sum += value
            }
        }
        resultChan <- sum
    }
    
    func main() {
        runtime.GOMAXPROCS(runtime.NumCPU())
        LIMIT := 1000
        //用于被15除结果
        job1 := make(chan int, 1)
        //用于被3,5除结果
        job2 := make(chan int, 2)
    
        t_start := time.Now()
        go get_sum_of_divisible(LIMIT, 15, job1)
        go get_sum_of_divisible(LIMIT, 3, job2)
        go get_sum_of_divisible(LIMIT, 5, job2)
    
        sum15 := <-job1
        sum3, sum5 := <-job2, <-job2
    
        sum := sum3 + sum5 - sum15
        t_end := time.Now()
        fmt.Println(sum)
        fmt.Println(t_end.Sub(t_start))
    }

    2、Channel通道:提供了协程之间的通信方式以及运行同步机制

    案例:假设训练定点投篮和三分投篮,教练在计数

    如果向channel里面写信息,必须有配对的取信息的一端;假如把下面的go count(c)注释掉,则不会有打印数据

    package main
    
    import (
        "fmt"
        "strconv"
        "time"
    )
    
    func fixed_shooting(msg_chan chan string) {
        i := 1
        for {
            msg_chan <- "fixed shooting"
            var str string = strconv.Itoa(i)
            fmt.Println("continue fixed shooting..." + str)
            i++
        }
    }
    
    func count(msg_chan chan string) {
        for {
            msg := <-msg_chan
            fmt.Println(msg)
            time.Sleep(time.Second * 1)
        }
    }
    
    func main() {
        var c chan string
        c = make(chan string)
    
        go fixed_shooting(c)
        go count(c)
    
        var input string
        fmt.Scanln(&input)
    }

    加一个三分投篮方法,可以看出,写入channel中的数据,必须读取出来才能再次写入,如果没有读取出来,再次写入会失败

    package main
    
    import (
        "fmt"
        "strconv"
        "time"
    )
    
    func three_point_shooting(msg_chan chan string) {
        i := 1
        for {
            var str string = strconv.Itoa(i)
            msg_chan <- "three point shooting--" + str
            i++
        }
    }
    
    func fixed_shooting(msg_chan chan string) {
        i := 1
        for {
            var str string = strconv.Itoa(i)
            msg_chan <- "fixed shooting--" + str
            i++
        }
    }
    
    func count(msg_chan chan string) {
        for {
            msg := <-msg_chan
            fmt.Println(msg)
            time.Sleep(time.Second * 1)
        }
    }
    
    func main() {
        var c chan string
        c = make(chan string)
    
        go fixed_shooting(c)
        go three_point_shooting(c)
        go count(c)
    
        var input string
        fmt.Scanln(&input)
    }

    结果图如下,结果是交替输出的,也就是channel中输入的必须输出后才能再次输入

    3、Channel通道方向

    var c chan string  可读写channel,可写入也可读取

    var c chan<- string  只写channel,只能写入

    var c <-chan string  只读channel,只能读取

    4、多通道(Select)

    案例中,select依次检查每个channel是否有消息传递过来,如果有就输出;如果同时有多个消息到达,select随机选择一个channel来从中读取消息;如果没有一个channel有消息到达,那么select语句就阻塞在这里一直等待。select 语句也可以有default片段,case不符合时会执行default语句片段。select中case、default类似switch中case、default

    下面case中使用了time.After,可以这样理解,main函数也是一个channel,time.After让main阻塞指定时间后,读出时间消息(案例中没有用变量存储返回的时间)

    package main
    
    import (
        "fmt"
        "time"
    )
    
    func fixed_shooting(msg_chan chan string) {
        var times = 3
        var t = 1
        for {
            if t <= times {
                msg_chan <- "fixed shooting"
            }
            t++
            time.Sleep(time.Second * 1)
        }
    }
    
    func three_point_shooting(msg_chan chan string) {
        var times = 3
        var t = 1
        for {
            if t <= times {
                msg_chan <- "three point shooting"
            }
            t++
            time.Sleep(time.Second * 1)
        }
    }
    
    func main() {
        c_fixed := make(chan string)
        c_3_point := make(chan string)
    
        go fixed_shooting(c_fixed)
        go three_point_shooting(c_3_point)
    
        go func() {
            for {
                select {
                case msg1 := <-c_fixed:
                    fmt.Println(msg1)
                case msg2 := <-c_3_point:
                    fmt.Println(msg2)
                case <-time.After(time.Second * 5):
                    fmt.Println("timeout check again...")
                }
            }
        }()
    
        var input string
        fmt.Scanln(&input)
    }

    结果图

    5、Channel Buffer通道缓冲区:一般我们定义的channel都是同步的,也就是说接受端和发送端彼此等待对方OK才开始。但是如果执行了channel缓冲区大小,那么消息的发送和接收是异步的,除非channel缓冲区已经满了

    package main
    
    import (
        "fmt"
        "strconv"
        "time"
    )
    
    func shooting(msg_chan chan string) {
        var group = 1
        for {
            for i := 1; i <= 10; i++ {
                msg_chan <- strconv.Itoa(group) + ":" + strconv.Itoa(i)
            }
            group++
            time.Sleep(time.Second * 5)
        }
    }
    
    func count(msg_chan chan string) {
        for {
            fmt.Println(<-msg_chan)
        }
    }
    
    func main() {
        var c = make(chan string, 20)
        go shooting(c)
        go count(c)
        var input string
        fmt.Scanln(&input)
    }
  • 相关阅读:
    python:一个比较有趣的脚本
    opencv:图像模糊处理
    opencv:基本图形绘制
    opencv:摄像头和视频的读取
    C++:lambda表达式
    opencv:傅里叶变换
    opencv:创建滑动条
    opencv:通过滑动条调节亮度和对比度
    【源码】防抖和节流源码分析
    【css】最近使用的两种图标字体库
  • 原文地址:https://www.cnblogs.com/hujiapeng/p/9651701.html
Copyright © 2011-2022 走看看