zoukankan      html  css  js  c++  java
  • Go基础05

    1 并发和并行

    1 并发:同一时间段内,多个任务在执行(单个cpu,执行多个任务)
    2 并行:同一时刻,多个任务在执行(多个cpu的支持)
    

    2 goroutine

    package main
    
    import (
    	"fmt"
    	"runtime"
    	"time"
    )
    //goroutine--->协程---2kb大小,100
    //线程----》几个m
    //go协程会复用线程
    
    // goroutine之间通信,通过 信道channel 通信
    //go推崇用信道通信,而不推崇用共享变量通信(锁,死锁)
    
    //启动一个goroutine
    func test()  {
    	fmt.Println("go go go")
    }
    
    
    //	//go语言中,主线程不会等待goroutine执行完成,要等待它结束需要自己处理
    
    // go 关键字开启goroutine,一个goroutine只占2kb,会自动扩容
    
    /*
    go语言的GMP模型
    	-G:开的goroutine
    	-M:M当成操作系统真正的线程,实际上是用户线程(用户线程)
    	-P:Processor:现在版本默认情况是cpu核数(可以当做cpu核数)
    	用户线程,操作系统线程
    	python中,开的线程开出用户线程,用户线程跟操作系统线程1:1的对应关系
    	某些语言,用户线程和操作系统线程是n:1的关系
    	go语言,用户线程和操作系统线程是 n:m的关系
     */
    func main() {
    		//设置P的大小,认为是cpu核数即可
    		runtime.GOMAXPROCS(1)
    		fmt.Println("主线程开始执行")
    		go func() {
    			for  {
    				fmt.Println("xxxx")
    			}
    		}()
    		//for i:=0;i<10;i++ {
    		//	go func(){
    		//		for  {
    		//			fmt.Println("我是死循环")
    		//
    		//		}
    		//
    		//	}()
    		//}
    		time.Sleep(10*time.Second)
    		fmt.Println("主线程结束执行")
    }
    

    3 信道(通道)

    package main
    
    import (
    	"fmt"
    	"time"
    )
    
    //不同goroutine之间通信
    //通过channel实现
    
    func main() {
    	//1 定义channel
    	var c chan int
    	//2 信道的零值(引用类型,空值为nil,当做参数传递时,不需要取地址,改的就是原来的,需要初始化再使用)
    	fmt.Println(c)
    	//3 信道初始化
    	c=make(chan int)  //数字暂时先不关注
    	//4 信道的放值  (注意赋值和放值)
    	//c<-1
    	//c=12  //赋值报错
    	//5 信道取值
    	//<-c
    	//6 取出来赋值给一个变量 int
    	//var a int
    	//a=<-c
    	//a:=<-c
    
    	//7 信道默认不管放值还是取值,都是阻塞的
    
    	//c是引用类型
    	go test1(c)
    
    	a:=<-c  //阻塞   不但实现了两条协程之间通信,还实现了等待协程执行结束
    	fmt.Println(a)
    
    }
    
    func test1(a chan int)  {
    	fmt.Println("go go go ")
    	time.Sleep(1*time.Second)
    	//往信道中放一个值
    	a<-10 //阻塞
    
    
    }
    
    
    
    package main
    
    //信道小例子
    //程序有一个数中 每一位的平方和与立方和,然后把平方和与立方和相加并打印出来
    
    import (
    	"fmt"
    	"time"
    )
    
    func calcSquares(number int, squareop chan int) {
    	sum := 0  //总和
    	for number != 0 {
    		digit := number % 10   //589对10取余数,9   8   5
    		sum += digit * digit  //sum=9*9   8*8     5*5
    		number /= 10         //num=58    5       0
    	}
    	time.Sleep(2*time.Second)
    	squareop <- sum
    }
    
    func calcCubes(number int, cubeop chan int) {
    	sum := 0
    	for number != 0 {
    		digit := number % 10
    		sum += digit * digit * digit
    		number /= 10
    	}
    	time.Sleep(1*time.Second)
    	cubeop <- sum
    }
    
    //func calcSquares(number int, squareop chan int) int{
    //	sum := 0  //总和
    //	for number != 0 {
    //		digit := number % 10   //589对10取余数,9   8   5
    //		sum += digit * digit  //sum=9*9   8*8     5*5
    //		number /= 10         //num=58    5       0
    //	}
    //	time.Sleep(2*time.Second)
    //	return sum
    //}
    //
    //func calcCubes(number int, cubeop chan int) int{
    //	sum := 0
    //	for number != 0 {
    //		digit := number % 10
    //		sum += digit * digit * digit
    //		number /= 10
    //	}
    //	time.Sleep(2*time.Second)
    //	return sum
    //}
    
    func main() {
    	ctime:=time.Now().Unix()
    	fmt.Println(ctime)
    	number := 589
    	sqrch := make(chan int)
    	cubech := make(chan int)
    	//num1:=calcSquares(number, sqrch)
    	//num2:=calcCubes(number, cubech)
    	go calcSquares(number, sqrch)
    	go calcCubes(number, cubech)
    	squares, cubes := <-sqrch, <-cubech
    	//squares:= <-sqrch
    	//cubes:=<-cubech
    	fmt.Println("Final output", squares + cubes)
    	ttime:=time.Now().Unix()
    	fmt.Println(ttime)
    	fmt.Println(ttime-ctime)
    }
    
    package main
    
    import "fmt"
    
    //信道的死锁现象,默认都是阻塞的,一旦有一个放,没有人取  或者一个人取,没有人放,就会出现死锁
    
    //func main() {
    //	//var c chan int =make(chan int )
    //
    //	//c<-1  //其实放不进去,阻塞在这,就死锁了
    //	//<-c     //没有,取不到,阻塞在这,就死锁了
    //
    //}
    
    
    //单向信道
    //func sendData(sendch chan<- int) {
    //	sendch <- 10
    //}
    //
    //func main() {
    //	//sendch := make(chan<- int)   //定义了一个只写信道
    //	sendch := make(chan int)   //定义了一个可读可写信道
    //	go sendData(sendch)        //传到函数中转成只写信道,在goroutine中,只负责写,不能往外读,主协程读
    //	fmt.Println(<-sendch)   //只写信道一旦读,就有问题
    //}
    
    
    
    ///3 关闭信道
    //func main() {
    //	sendch := make(chan int)
    //	//关闭信道
    //	//close(sendch)
    //
    //	//信道可以用for循环循环
    //}
    
    
    // 信道关闭close(sendch) ,for循环循环信道,如果不关闭会报死锁,如果关闭了,放不进去,循环结束
    func producer(chnl chan int) {
    	for i := 0; i < 100; i++ {
    		fmt.Println("放入了",i)
    		chnl <- i
    	}
    	close(chnl)
    }
    func main() {
    	ch := make(chan int)
    	go producer(ch)
    	for v := range ch {
    		fmt.Println("Received ",v)
    	}
    }
    

    4 缓冲信道

    package main
    
    import (
    	"fmt"
    	"sync"
    	"time"
    )
    //缓冲信道:只在缓冲已满的情况,才会阻塞向缓冲信道,只有在缓冲为空的时候,才会阻塞从缓冲信道接收数据
    
    func main() {
    var c chan int =make(chan int,6)  //无缓冲信道数字是0
    
    2 长度 vs 容量
    //fmt.Println(len(c))  //目前放了多少
    //fmt.Println(cap(c)) //可以最多放多少
    3 WaitGroup  等待所有goroutine执行完成
    4  使用信道如何实现?
    func process1(i int,wg *sync.WaitGroup)  {
    	fmt.Println("started Goroutine ", i)
    	time.Sleep(2 * time.Second)
    	fmt.Printf("Goroutine %d ended
    ", i)
    	//一旦有一个完成,减一
    	wg.Done()
    }
    func main() {
    	var wg sync.WaitGroup   //没有初始化,值类型,当做参数传递,需要取地址
    	//fmt.Println(wg)
    	for i:=0;i<10;i++ {
    		wg.Add(1) //启动一个goroutine,add加1
    		go process1(i,&wg)
    	}
    	wg.Wait() // 一直阻塞在这,知道调用了10个done,计数器减到零
    }
       var wg sync.WaitGroup   //没有初始化,值类型,当做参数传递,需要取地址
        wg.Add(1)
        wg.Done()
        wg.Wait()
    

    5 Select

    package main
    
    import (
    	"fmt"
    	"time"
    )
    // 随机选取
    func server1(ch chan string) {
    	ch <- "from server1"
    }
    func server2(ch chan string) {
    	ch <- "from server2"
    
    }
    func main() {
    	output1 := make(chan string)
    	output2 := make(chan string)
    	go server1(output1)
    	go server2(output2)
    	time.Sleep(1 * time.Second)
        for {
    	select {
           time.Sleep(1 * time.Second)
    	case s1 := <-output1:
    		fmt.Println(s1)
    	case s2 := <-output2:
    		fmt.Println(s2)
            default:
            ...(做其他事)
    	}
        }
    }
    
    

    6 mutex

    package main
    
    import (
    	"fmt"
    	"sync"
    )
    var m sync.Mutex
    m.Lock()
    m.Unlock() //是个值类型,函数传递需要传地址
    // 使用锁的场景:多个goroutine通过共享内存在实现数据通信
    // 临界区:当程序并发地运行时,多个 [Go 协程]同时修改共享资源的代码。这些修改共享资源的代码称为临界区。
    //如果在任意时刻只允许一个 Go 协程访问临界区,那么就可以避免竞态条件。而使用 Mutex 可以达到这个目的
    channel 来做
    	ch := make(chan bool, 1) 
    	ch <- true  // 缓冲信道放满了,就会阻塞
    	x = x + 1
    	<- ch
    // 不同goroutine之间传递数据:共享变量,  通过信道
    // 如果是修改共享变量,建议加锁
    //如果是协程之间通信,用信道
    

    7 异常处理

    defer ...   //压栈出栈 执行顺序 先定义的最后执行,释放资源
    recover() 恢复
    panic 主动报错
    test(){
        def func(){
            if e:=recover();e!=nil{
                fmt.Println(e)
            }
            //没错走这里 类似于finally 写个return 
        }()  
    }
    
    永远不要高估自己
  • 相关阅读:
    一、ThinkPHP的介绍
    一、ThinkPHP的介绍
    perl 爬虫两个技巧
    perl 爬虫两个技巧
    perl 爬取上市公司业绩预告
    perl lwp get uft-8和gbk
    perl lwp get uft-8和gbk
    perl 爬取同花顺数据
    perl 爬取同花顺数据
    php 接口示例
  • 原文地址:https://www.cnblogs.com/liqiangwei/p/14521303.html
Copyright © 2011-2022 走看看