• goroutine


     

    并发:逻辑上具备同时处理多个任务的能力(单核,上下文切换)

    并行:物理上同一时刻执行多个并发任务(多核,互不影响)

    package main
    
    import (
    	"fmt"
    	"time"
    )
    
    var c int
    
    func counter() int {
    	c++
    	return c
    }
    
    func main() {
    	a := 100
    	go func(x, y int) {
    		time.Sleep(time.Second) //goroutine在main逻辑之后执行
    		fmt.Println("go:", x, y)
    	}(a, counter()) //立即计算并赋值
    	a += 100
    	fmt.Println("main", a, counter())
    	time.Sleep(time.Second * 3) //等goroutine结束
    }
    

      

    进程退出并不会等并发任务执行结束,可用channel阻塞,然后发出退出信号

    package main
    
    import (
    	"fmt"
    	"time"
    )
    
    func main() {
    	exit := make(chan struct{})
    	go func() {
    		time.Sleep(time.Second)
    		fmt.Println("goroutine done")
    		close(exit) //关闭通道,发出信号
    	}()
    	fmt.Println("main start...")
    	<-exit //通道关闭,立即解除阻塞
    	fmt.Println("main end...")
    }
    

      

    等待多个任务结束,使用sync.WaitGroup,通过设定计数器,让每个goroutine在退出前递减,直至归零时解除阻塞

    package main
    
    import (
    	"fmt"
    	"sync"
    	"time"
    )
    
    func main() {
    	var wg sync.WaitGroup
    	for i := 0; i < 10; i++ {
    		wg.Add(1) //累加计数
    
    		go func(id int) {
    			defer wg.Done() //递归计数
    			time.Sleep(time.Second)
    			fmt.Println("goroutine", id)
    		}(i)
    	}
    	fmt.Println("start")
    	wg.Wait() //阻塞,直至计数归零
    	fmt.Println("stop")
    }
    

      

    channel限制并发数

    package main
    
    import (
    	"fmt"
        "sync"
        "time"
    )
    
    var wg = sync.WaitGroup{}
    
    func main() {
    	ch := make(chan int, 2)
    	for i := 0; i < 100; i++ {
    		go run(ch, i)
    	}
    	wg.Wait()
    }
    
    func run(ch chan int, i int) {
    	wg.Add(1)
    	defer wg.Done()
    	ch <- i
        fmt.Println(i)
        time.Sleep(1*time.Second)
    	<-ch
    }
    

      

    GOMAXPROCS

    与逻辑核数相等

    package main
    
    import (
    	"fmt"
    	"math"
    	"runtime"
    	"sync"
    )
    
    func count() {
    	x := 0
    	for i := 0; i < math.MaxUint32; i++ {
    		x += i
    	}
    	fmt.Println(x)
    }
    
    func test(n int) {
    	for i := 0; i < n; i++ {
    		count()
    	}
    }
    
    func test2(n int) {
    	var wg sync.WaitGroup
    	wg.Add(n)
    	for i := 0; i < n; i++ {
    		go func() {
    			count()
    			wg.Done()
    		}()
    	}
    	wg.Wait()
    }
    
    func main() {
    	n := runtime.GOMAXPROCS(0)
    	test2(n)
    }
    

      

    可在多处使用Wait阻塞,它们都能收到通知

    package main
    
    import (
    	"fmt"
    	"sync"
    	"time"
    )
    
    func main() {
    	var wg sync.WaitGroup
    	wg.Add(1)
    
    	go func() {
    		wg.Wait()
    		fmt.Println("wait exit")
    	}()
    
    	go func() {
    		time.Sleep(time.Second)
    		fmt.Println("done")
    		wg.Done()
    	}()
    	wg.Wait()
    	fmt.Println("main exit")
    }
    

     

    多个goroutine进行通信

    方式一:全局变量(加锁)

    package main
    
    import (
    	"fmt"
    	"sync"
    	"time"
    )
    
    var (
    	m    = make(map[int]int)
    	lock sync.Mutex
    )
    
    type task struct {
    	n int
    }
    
    func calc(t *task) {
    	sum := 1
    	for i := 1; i <= t.n; i++ {
    		sum *= i
    	}
    	lock.Lock()
    	m[t.n] = sum
    	lock.Unlock()
    }
    
    func main() {
    	for i := 1; i < 10; i++ {
    		t := &task{n: i}
    		go calc(t)
    	}
    	time.Sleep(time.Second * 2)
    
    	lock.Lock()
    	for k, v := range m {
    		fmt.Printf("%d! is %v
    ", k, v)
    	}
    	lock.Unlock()
    }
    

      

    用到goroutine时编译加-race竞争检测

    方式二:channel 

    channel概念

    • 类似pipe
    • 先进先出
    • 线程安全,多个goroutine同时访问,不需要加锁
    • channel是有类型的,一个整数的channel只能存放整数

    channel申明

    • var 变量名 chan 类型
    • var test chan int
    • var test chan map[string]string

    channel关闭

    方法一:v,ok := <-chan

    package main
    
    import (
    	"fmt"
    )
    
    func main() {
    	ch := make(chan int, 10)
    	for i := 0; i < 10; i++ {
    		ch <- i
    	}
    	close(ch)
    	for {
    		b, ok := <-ch
    		if ok == false {
    			break
    		}
    		fmt.Println(b)
    	}
    }
    

      

    方式二:

    for v := range chan

    channel读写

    package main
    
    import (
    	"fmt"
    	"time"
    )
    
    func write(ch chan int) {
    	for i := 0; i < 100; i++ {
    		ch <- i
    	}
    }
    
    func read(ch chan int) {
    	var a int
    	for {
    		a = <-ch
    		fmt.Println("read", a)
    	}
    
    }
    
    func main() {
    	intChan := make(chan int, 10)
    	go write(intChan)
    	go read(intChan)
    	time.Sleep(time.Second)
    }
    

      

    判断10000内的素数

    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
    		}
    	}
    	exitChan <- true
    }
    
    func main() {
    	taskChan := make(chan int, 1000)
    	resChan := make(chan int, 1000)
    	exitChan := make(chan bool, 8)
    
    	go func() {
    		for i := 1; i < 10000; i++ {
    			taskChan <- i
    		}
    		close(taskChan)
    	}()
    
    	for i := 0; i < 8; i++ {
    		go calc(taskChan, resChan, exitChan)
    	}
    
    	go func() {
    		for i := 0; i < 8; i++ {
    			<-exitChan
    		}
    		close(resChan)
    	}()
    
    	for v := range resChan {
    		fmt.Println(v)
    	}
    }
    

      

    定时器

    package main
    
    import (
    	"fmt"
    	"time"
    )
    
    func main() {
    	t := time.NewTicker(time.Second)
    	for v := range t.C {
    		fmt.Println("hello", v)
    	}
    t.Stop() }

      

      

    超时控制

    package main
    
    import (
    	"fmt"
    	"time"
    )
    
    func main() {
    	select {
    	case <-time.After(time.Second):
    		fmt.Println("timeout")
    	}
    }
    

      

  • 相关阅读:
    【转】JVM 堆内存设置原理
    【转】Java八种基本数据类型的比较及其相互转化
    8月12日
    并发与竞争
    高通gpio配置输出
    创建一个字符设备的基本流程
    4月2号 字符设备驱动实验
    3.30学习遇到卡死点
    断言函数的用法
    12.02 下午
  • 原文地址:https://www.cnblogs.com/hongpeng0209/p/9108048.html
Copyright © 2020-2023  润新知