• go语言5 接口, 并发与并行, go协程, 信道, 缓冲信道, 异常处理, python进程线程


    1 接口

    //一系列方法的集合,规范了子类的行为,    
        -python和go都属于鸭子类型,非侵入式接口
        -java:侵入式接口
    package main
    
    import "fmt"
    
    //1 定义一个接口,(规范行为,没有具体实现)
    type DuckInterface interface {
        Run()
        Speak()
    }
    
    //定义一个TDuck结构体
    type TDuck struct {
        name string
        age int
        wife string
    }
    //TDuck实现接口(实现接口中的所有方法)
    func (t TDuck)Run()  {
        fmt.Println("我是唐老鸭,我的名字是",t.name,"我说人话")
    }
    func (t TDuck)Speak()  {
        fmt.Println("我是唐老鸭,我的名字是",t.name,"我学人走路")
    }
    
    //定义一个RDuck结构体
    type RDuck struct {
        name string
        age int
    }
    //RDuck实现接口(实现接口中的所有方法)
    func (t RDuck)Run()  {
        fmt.Println("我是普通肉鸭,我的名字是",t.name,"我阿嘎嘎叫")
    }
    func (t RDuck)Speak()  {
        fmt.Println("我是普通肉鸭,我的名字是",t.name,"我歪歪扭扭走路")
    }
    
    
    // 5 有名空接口
    type EmptyInterface interface {
    
    }
    
    func main() {
        //2 实例化得到TDuck和RDuck两个对象
        //t:=TDuck{"鸡哥",88,"凤姐"}
        r:=RDuck{"普通鸭子",2}
        //t.Run()
        //t.Speak()
        //r.Run()
        //r.Speak()
        //接口也是一个类型(可以定义一个变量是接口类型)
        // 同一类事物的多种形态
        //var d DuckInterface
        //d=t
        ////d=r
        //d.Speak()
        //d.Run()
        //想再去t的属性,name,age,wife
        //test(t)
        //test(r)
    
        // 5 空接口
        //-只要一个类型,实现接口所有的方法,就叫实现该接口
        //-如果一个接口是空的,一个方法都没有,所有类型都实现了空接口
        //-任意类型,都可以赋值给空接口类型
        //var a EmptyInterface
        //a=1
        //a="xx"
        //a=[3]int{1,2,3}
    
        //6 接口类型空值(nil)
        //var a EmptyInterface
        //fmt.Println(a)
    
        //7 匿名空接口
        // interface{}
        test(1)
        test(r)
        test(1.2)
    }
    
    ////3 类型断言
    //func test(d DuckInterface)  {
    //    //d.Run()
    //    //d.Speak()
    //    //var t TDuck
    //    //t=d.(TDuck)
    //    t:=d.(TDuck) //断言d是TDuck类型,如果正确,就会把d转成t,否则会报错
    //    fmt.Println(t.name)
    //    fmt.Println(t.wife)
    //    t.Speak()
    //    t.Run()
    //}
    
    //4 类型选择
    //func test(d DuckInterface)  {
    //    switch a:=d.(type) {
    //    case TDuck:
    //        fmt.Println(a.wife)
    //        fmt.Println("你是TDuck类型")
    //    case RDuck:
    //        fmt.Println(a.name)
    //        fmt.Println("你是RDuck类型")
    //    default:
    //        fmt.Println("不知道是什么类型")
    //    }
    //}
    
    //7 匿名空接口
    //func test(i interface{})  {  // 也可以
    func test(i EmptyInterface)  {  // EmptyInterface是上面定义的有名匿名接口
        fmt.Println(i)
    }
    package main
    
    // 1 实现多个接口
    //type DuckInterface1 interface {
    //    Run()
    //    Speak()
    //}
    //
    //type HumanInterface interface {
    //    Drive()
    //}
    //
    ////定义一个TDuck结构体
    //type TDuck1 struct {
    //    name string
    //    age int
    //    wife string
    //}
    ////TDuck实现接口(实现接口中的所有方法)
    //func (t TDuck1)Run()  {
    //    fmt.Println("我是唐老鸭,我的名字是",t.name,"我说人话")
    //}
    //func (t TDuck1)Speak()  {
    //    fmt.Println("我是唐老鸭,我的名字是",t.name,"我学人走路")
    //}
    ////实现HumanInterface接口
    //func (t TDuck1)Drive()  {
    //    fmt.Println("我是唐老鸭,我开车")
    //}
    
    // 2 接口嵌套
    type DuckInterface1 interface {
        Run()
        Speak()
    }
    
    type HumanInterface interface {       // 要实现这个接口,必须实现Drive(),Run(),Speak()方法
        DuckInterface1
        //相当于
        //Run()
        //Speak()
        Drive()
    }
    
    func main() {
        //t:=TDuck1{"鸡哥",18,"凤姐"}
        //var d DuckInterface1
        //var h HumanInterface
        //d=t
        //d.Run()
        //d.Speak()
        //h=t
        //h.Drive()
    
    }

    2 并发和并行

    //并发:假如在他晨跑时,鞋带突然松了。于是他停下来,系一下鞋带,接下来继续跑
    //并行:如这个人在慢跑时,还在用他的 iPod 听着音乐

    3 go协程

    //go协程--》goroutine,并不是真正的协程(线程+协程,语言层面处理了,不需要开发者去关注) 
    // 如果要go线程并行,需要有个参数配置
    
    package main
    
    import (
        "fmt"
        "time"
    )
    
    func hello()  {
        fmt.Println("go go go!")
    }
    func main() {
        fmt.Println("主函数开始")
        go hello() //通过go关键字,开启goroutine,并发执行
        go hello()
        go hello()
        go hello()
    
        fmt.Println("主函数结束")
        time.Sleep(2*time.Second)
    }

    4 信道

    //goroutine直接通信
    //go语言不推崇共享变量方法做通信,而推崇管道通信channel(信道)
    // 信道(管道)
    package main
    import (
        "fmt"
        "time"
    )
    
    func main() {
        //1 信道也是一个变量(需要指明运输的类型)
        //var a chan int //定义一个int类型信道
    
        //2 信道的0值,nil类型,它是一个引用
        //fmt.Println(a)
    
        //3 信道初始化
        //var a chan int=make(chan int)
        //fmt.Println(a)
    
        //4 信道的放值,和取值
        //var a chan int=make(chan int)
        //a<-1   //放值,把1放到信道中
        ////var b int=<-a    //取值
        //<-a    //取值
    
        //5 默认情况下,信道的放值和取值都是阻塞的(一次一个都放不进去) (放值必须有人来接,否则放不进去)
        fmt.Println("开始")
        var a chan bool=make(chan bool)
        //信道是引用类型
        go hello1(a)
        // time.Sleep(2*time.Second)
        <-a        // hang住,只有里面有值,取出
    }
    
    func hello1(a chan bool)  {
        fmt.Println("go go go")
        a<-true      // 当如果没有人取值,会一直hang住,知道有人取为去,才能放入
        fmt.Println("xxx")  // 当主线程取完值,控制台运行结束,不会打印xxx
    }
    //信道案例
    
    package main
    /*
    输入 453  计算每一位的平方和和每一位的立方和的和
    squares = (4 * 4) + (5 * 5) + (3 * 3)
    cubes = (4 * 4 * 4) + (5 * 5 * 5) + (3 * 3 * 3)
    output = squares + cubes
     */
    
    import (
        "fmt"
    )
    
    func calcSquares(number int, squareop chan int) {
        sum := 0
        for number != 0 {
            digit := number % 10   //% 取余数 453对10取余数--》3--》5--》4
            sum += digit * digit
            number /= 10          // /除以  453除以10----》45--》5--》0
        }
        squareop <- sum
    }
    
    func calcCubes(number int, cubeop chan int) {
        sum := 0
        for number != 0 {
            digit := number % 10
            sum += digit * digit * digit
            number /= 10
        }
        cubeop <- sum
    }
    
    func main() {
        number := 4535
        sqrch := make(chan int)
        cubech := make(chan int)
        go calcSquares(number, sqrch)
        go calcCubes(number, cubech)
        squares, cubes := <-sqrch, <-cubech
        //squares:= <-sqrch
        //cubes := <-cubech
        fmt.Println("Final output", squares + cubes)
    }
    package main
    func main() {
        //1 死锁
    
        //var a chan int=make(chan int)
        //a<-1  //一直阻塞在这,报死锁错误
        //<-a     //一直阻塞在这,报死锁错误
    
        //2 单向信道(只写或者只读)
        //sendch := make(chan int) //定义一个可写可读信道
        //go sendData(sendch)
        //fmt.Println(<-sendch)  //只能往里写值,取值报错
    
        //3 信道的关闭 close
        //sendch := make(chan int)
        //close(sendch)
    
    }
    func sendData(sendch chan<- int) {  //转成只写信道
        sendch <- 10
        //<-sendch  //只要读就报错
    }
    package main
    
    import (
        "fmt"
    )
    
    func producer(chnl chan int) {
        for i := 0; i < 10; i++ {
            chnl <- i
        }
        close(chnl)    // 关闭信道
    }
    func main() {
        ch := make(chan int)
        go producer(ch)
        for v := range ch {  //如果信道没关闭,一直取值,直到没有值,会报死锁
            fmt.Println("Received ",v)
        }
    }

    5 缓冲信道

    //有缓冲信道(信道可以放多个值)
    
    package main
    import (
        "fmt"
        "sync"
        "time"
    )
    
    func main() {
        //1 有缓冲信道的定义和死锁问题
        //var a chan int =make(chan int,4)  //长度为4的有缓冲信道
        //a<-1
        //a<-2
        ////a<-3
        ////a<-4
        ////管子满了
        ////a<-5  //报死锁错误
        ////推断出无缓冲信道 var a chan int =make(chan int,0)
        //fmt.Println(<-a)
        //fmt.Println(<-a)
        ////管子没有东西了,再取,报死锁
        //fmt.Println(<-a)
    
        //2 信道的容量和长度
        //长度是目前管道中有几个值,容量是管道最多能容纳多少值
        //var a chan int =make(chan int,4)
        //fmt.Println(len(a))
        //fmt.Println(cap(a))
        //a<-1
        //a<-2
        //fmt.Println(len(a))
        //fmt.Println(cap(a))
    
        //3 小案例(通过信道实现goroutine的同步)    第一种实现线程同步方式(常用)
        //var a chan int =make(chan int,3)
        ////b:=<-a
        //go test3(a)
        //
        //fmt.Println(<-a)
        //
        //fmt.Println(<-a)
    
        //4 通过waitgroup实现同步       第二种实现线程同步方式
            no := 3
            var wg sync.WaitGroup  //值类型,没有初始化,有默认值
            for i := 0; i < no; i++ {
                wg.Add(1)
                go process(i, &wg)   // 因为是值类型,所以要取地址
            }
            wg.Wait() //add了几次,必须有几个wg.Done()对应,否则一直等在这
            fmt.Println("All go routines finished executing")
    }
    
    func process(i int, wg *sync.WaitGroup) {
        fmt.Println("started Goroutine ", i)
        time.Sleep(2 * time.Second)
        fmt.Printf("Goroutine %d ended
    ", i)
        wg.Done()
    }
    
    
    //func test3(a chan int)  {
    //    a<-1
    //
    //    time.Sleep(time.Second*2)
    //    fmt.Println("假设我在运算")
    //
    //    a<-2
    //    close(a)
    //
    //}

    6 异常处理

    //异常处理
    package main
    
    import "fmt"
    
    //func main() {
    //    f1()
    //    f2()
    //    f3()
    //}
    //func f1()  {
    //    fmt.Println("f1")
    //}
    //
    //func f2()  {
    //    fmt.Println("f2")
    //    //如果这个地方出了异常
    //}
    //func f3()  {
    //    fmt.Println("f3")
    //}
    
    //defer:延迟执行,即便程序出现严重错误,也会执行
    //panic:主动抛出异常 raise
    //recover:恢复程序,继续执行
    
    //func main() {
    //    //defer fmt.Println("我最后才执行")  //先注册,等函数执行完成后,逆序执行defer注册的代码
    //    //defer fmt.Println("ddddd")
    //    defer func() {        // 匿名函数
    //        fmt.Println("我最后才执行")
    //    }()
    //    defer func() {
    //        fmt.Println("我最后才执行")
    //        //出异常
    //        //这个代码执行不到了, 再执行之前的defer
    //    }()
    //
    //    fmt.Println("111")
    //    fmt.Println("222")
    //    panic("我出错了")  //主动抛出异常
    //    //var a []int =make([]int,2,3)
    //    //fmt.Println(a[9])
    //    fmt.Println("这句话还会执行吗 ?不会了")
    //}
    
    //在defer中恢复程序,继续执行
    func main() {
    
        f1()
        f2()
        f3()
    }
    func f1()  {
        fmt.Println("f1")
    }
    
    func f2()  {
        defer func() {        // 异常处理模板
            //recover() //恢复程序继续执行f3
            if err:=recover();err!=nil{  // recover()有返回值为异常信息err 如果不为nil(空),表示出了异常
                fmt.Println(err)  //把异常信息打印出来
            }
        }()
        fmt.Println("f2")
        //如果这个地方出了异常
        panic("我出错了")    // 报错,执行上面的defer
    
        fmt.Println("永远执行不到")
    }
    func f3()  {
        fmt.Println("f3")
    }
    
    // python中
    //print('ssss')
    //try:
    //    print('ssss')
    //    raise("xxxx")
    //    print('我永远不会执行')
    //except Exception as e:
    //    print(e)
    //finally:
    //    print('我永远会执行')
    
    //go 中
    //print('ssss')
    //defer func() {       // 异常处理模板
    //    if err:=recover();err!=nil{    
    //        fmt.Println(err)
    //    }
    //    //finally 写在这
    //    print('我永远会执行')
    //}()
    //print('ssss')
    //panic("xxxx")
    //print('我永远不会执行')

    补充

    1 进程,线程,协程

    # python中为什么让你开进程,由于cpython解释器,有GIL锁,同一时刻,只能有一个线程执行
    # 开进程--》相当于开了多个线程,重新起了一个cpython解释器,运行代码
  • 相关阅读:
    软件测试技术实战 设计、工具及管理(51Testing软件测试网作品系列)
    MATLAB智能算法超级学习手册
    HTML与CSS入门经典(第9版)
    深入理解Android 5 源代码
    中文版Dreamweaver CS6基础培训教程(第2版)
    可用性测试手册(第2版)
    网络综合布线系统与施工技术第4版
    PHP核心技术与最佳实践(第2版)
    [OC Foundation框架
    [OC Foundation框架
  • 原文地址:https://www.cnblogs.com/ludingchao/p/12774037.html
Copyright © 2020-2023  润新知