• Golang之并发篇


    进程和线程
    
    A。进程是程序在操作系统中的一次执行过程,系统进行资源分配和调度的一个独立单位。
    
    B。线程是进程的一个执行实体,是CPU调度和分派的基本单位,它是比进程更小的能独立运行的基本单位。
    
    C。一个进程可以创建和撤销多个线程;同一进程中的多个线程之间可以并发执行。

    并发和并行
    并发:多线程程序在一个核的cpu上运行
    并行:多线程程序在多个核的cpu上运行
    举例。。一个妈给一个碗给多个小孩喂饭,,是并发
        一个妈给每个小孩一人一个碗,就是并行

    并发                       并行

    协程和线程
    协程:独立的栈空间,共享堆空间,调度由用户自己控制,本质上有点类似于用户级协程,这些用户级线程的调度也是自己实现的。
    线程:一个线程上可以跑多个协程,协程是轻量级的线程。

    例子

    package main
    
    import (
        "fmt"
        "time"
    )
    
    func test() {
        var i int
        for {
            fmt.Println(i)
            time.Sleep(time.Second)
            i++
        }
    }
    func main() {
        go test() //起一个协程执行test()
        for {
            fmt.Println("i : runnging in main")
            time.Sleep(time.Second )
        }
    }

    -

    --

    设置Golang运行的cpu核数。

    1.8版本以上,默认跑多个核

    package main
    
    import (
        "fmt"
        "runtime"
    )
    
    func main() {
        num := runtime.NumCPU()
        runtime.GOMAXPROCS(num)
        fmt.Println(num)
    }

    并发计算

    package main
    
    import (
        "fmt"
        "sync"
        "time"
    )
    
    var (
        m    = make(map[int]uint64)
        lock sync.Mutex
    )
    
    type task struct {
        n int
    }
    
    func calc(t *task) {
        var sum uint64
        sum = 1
        for i := 1; i < t.n; i++ {
            sum *= uint64(i)
        }
        fmt.Println(t.n, sum)
        lock.Lock()
        m[t.n] = sum
        lock.Unlock()
    
    }
    
    func main() {
        for i := 0; i < 16; i++ {
            t := &task{n: i}
            go calc(t)//并发执行,谁快谁先出 
        }
        time.Sleep(10 * time.Second)
        //lock.Lock()
        //for k, v := range m {
        //    fmt.Printf("%d!=%v
    ", k, v)
        //}
        //lock.Unlock()
    }
    并发计算

     Channel

    channel概念
    a。类似unix中的管道(pipe)
    b.先进先出
    c。线程安全,多个goroutine同时访问,不需要枷锁
    d。channel是有类型的,一个整数的channel只能存整数

     channel声明

    var name chan string
    var age chan int
    var mapchan chan map[string]string
    var test chan student
    var test1 chan *student

    channel初始化

    使用make进行初始化
    var test chan int
    test = make(chan int,10)
    
    var test chan string
    test=make(chan string,10)

    channel基本操作

    从channel读取数据
    var
    testChan chan int testChan = make(chan int, 10) var a int a = <-testChan

    -从channel写入数据

    var testChan chan int
    testChan = make(chan int, 10)
    var a int = 10
    testChan <- a

    第一个例子

    package main
    
    import "fmt"
    
    type student struct {
        name string
    }
    
    func main() {
        var stuChan chan *student
        stuChan = make(chan *student, 10)
    
        stu := student{name: "stu001"}
    
        stuChan <- &stu
    
        var stu01 interface{}
        stu01 = <-stuChan
    
        var stu02 *student
        stu02, ok := stu01.(*student)
        if !ok {
            fmt.Println("can not convert")
            return
        }
        fmt.Println(stu02)
    }

    goroutine与channel

    package main
    
    import (
        "fmt"
        "time"
    )
    
    //起一个读的协程
    func write(ch chan int) {
        for i := 0; i < 1000; i++ {
            ch <- i
        }
    }
    
    func read(ch chan int) {
        for {
            var b int
            b = <-ch
            fmt.Println(b)
        }
    }
    
    func main() {
        intChan := make(chan int, 10)
        go write(intChan)
        go read(intChan)
        time.Sleep(10 * time.Second)
    }

    读,取,字符串

    package main
    
    import (
        "fmt"
        "time"
    )
    
    func sendData(ch chan string) {
        ch <- "Washington"
        ch <- "Tripoli"
        ch <- "London"
        ch <- "Beijing"
        ch <- "Tokio"
    }
    
    func getData(ch chan string) {
        var input string
        for {
            input = <-ch
            fmt.Println(input)
        }
    }
    
    func main() {
        ch := make(chan string)
        go sendData(ch)
        go getData(ch)
        time.Sleep(3 * time.Second)
    }
    读取字符串

     Channel缓冲区

    只能放一个元素的testChan
    var testChan chan int
    testChan = make(chan int)
    var a int
    a = <-testChan

    -

    testChan是带缓冲区的chan,一次可以放10个元素
    var
    testChan chan int testChan = make(chan int, 10) var a int = 10 testChan <- a

     -

    package main
    
    import (
        "fmt"
        "sync"
        "time"
    )
    
    var (
        m    = make(map[int]uint64)
        lock sync.Mutex
    )
    
    type task struct {
        n int
    }
    
    func calc(t *task) {
        var sum uint64
        sum = 1
        for i := 1; i < t.n; i++ {
            sum *= uint64(i)
        }
        fmt.Println(t.n, sum)
        lock.Lock()
        m[t.n] = sum
        lock.Unlock()
    }
    
    func main() {
        for i := 0; i < 16; i++ {
            t := &task{n: i}
            go calc(t)
        }
        time.Sleep(10 * time.Second)
        lock.Lock()
        for k, v := range m {
            fmt.Printf("%d!=%v
    ", k, v)
    
        }
        lock.Unlock()
    }
    goroutine_lock
    package main
    
    import (
        "fmt"
    )
    
    func calc(taskChan chan int, resChan chan int, exitChan chan bool) {
        for v := range taskChan {
            flag := true
            for i := 2; i < v; i++ {
                if v%i == 0 {
                    flag = false
                    break
                }
            }
            if flag {
                resChan <- v
            }
        }
        fmt.Println("exit")
        exitChan <- true
    }
    func main() {
        intChan := make(chan int, 1000)
        resultChan := make(chan int, 1000)
        exitChan := make(chan bool, 8)
        go func() {
            for i := 0; i < 10000; i++ {
                intChan <- i
            }
            close(intChan)
        }()
        for i := 0; i < 8; i++ {
            go calc(intChan, resultChan, exitChan)
        }
    
        //等待所有计算的goroutine全部退出
        go func() {
            for i := 0; i < 8; i++ {
                <-exitChan
                fmt.Println("wait goroute", i, "exited")
            }
            close(resultChan)
        }()
        for v := range resultChan {
            fmt.Println(v)
        }
    
    }
    goroutine_sync
    package main
    
    import "fmt"
    
    func send(ch chan int, exitChan chan struct{}) {
        for i := 0; i < 10; i++ {
            ch <- i
        }
        close(ch)
        var a struct{}
        exitChan <- a
    }
    func recv(ch chan int, exitChan chan struct{}) {
        for {
            v, ok := <-ch
            if !ok {
                break
            }
            fmt.Println(v)
        }
        var a struct{}
        exitChan <- a
    }
    func main() {
        var ch chan int
        ch = make(chan int, 10)
        exitChan := make(chan struct{}, 2)
    
        go send(ch, exitChan)
        go recv(ch, exitChan)
        var total = 0
        for _ = range exitChan {
            total++
            if total == 2 {
                break
            }
        }
    }
    goroutine_sync2

    检测管道是否关闭

    package main
    
    import "fmt"
    
    func main() {
        var ch chan int
        ch = make(chan int, 10)
        for i := 0; i < 10; i++ {
            ch <- i
        }
        close(ch)
        for {
            var b int
            b, ok := <-ch
            //检测管道是否关闭
            if ok == false {
                fmt.Println("chan is close")
                break
            }
            fmt.Println(b)
        }
    }
    检测管道是否关闭

     如何关闭chan

    1. 使用内置函数close进行关闭,chan关闭之后,for range遍历chan中
    已经存在的元素后结束
    2. 使用内置函数close进行关闭,chan关闭之后,没有使用for range的写法
    需要使用,v, ok := <- ch进行判断chan是否关闭

    chan的只读和只写

    只读的声明
    Var 变量的名字 <-chan int
    Var readChan <- chan int
    
    只写的声明
    Var 变量的名字 chan<- int
    Var writeChan chan<- int
    package main
    
    import "fmt"
    
    //只写chan
    func send(ch chan<- int, exitChan chan struct{}) {
        for i := 0; i < 10; i++ {
            ch <- i
        }
        close(ch)
        var a struct{}
        exitChan <- a
    }
    
    //只读chan
    func recv(ch <-chan int, exitChan chan struct{}) {
        for {
            v, ok := <-ch
            if !ok {
                break
            }
            fmt.Println(v)
        }
        var a struct{}
        exitChan <- a
    }
    
    func main() {
        var ch chan int
        ch = make(chan int, 10) //初始化chan
        exitChan := make(chan struct{}, 2)
    
        go send(ch, exitChan)
        go recv(ch, exitChan)
    
        var total = 0
        for _ = range exitChan {
            total++
            if total == 2 {
                break
            }
        }
    
    }
    只读只写示例chan

    不阻塞

    package main
    
    import "fmt"
    import "time"
    
    func main() {
        var ch chan int
        ch = make(chan int, 10)
        ch2 := make(chan int, 10)
        go func() {
            var i int
            for {
                ch <- i
                time.Sleep(time.Second)
                ch2 <- i * i
                time.Sleep(time.Second)
                i++
            }
        }()
        for {
            select {
            case v := <-ch:
                fmt.Println(v)
            case v := <-ch2:
                fmt.Println(v)
            case <-time.After(time.Second):
                fmt.Println("get data timeout")
                time.Sleep(time.Second)
            }
        }
    }
    chan不阻塞
  • 相关阅读:
    [团队项目]典型用户
    0415 操作系统_实验二、作业调度模拟程序
    0415 结对2.0评价
    复利计算- 结对2.0--复利计算WEB升级版
    0408汉堡
    复利计算- 结对1.0
    0405《构建之法》第四章读后感
    复利计算器4.0 【java版】
    复利计算器的单元测试结果
    操作系统 实验一、命令解释程序的编写实验
  • 原文地址:https://www.cnblogs.com/pyyu/p/8318417.html
Copyright © 2020-2023  润新知