• 设为首页
  • 点击收藏
  • 手机版
    手机扫一扫访问
    迪恩网络手机版
  • 关注官方公众号
    微信扫一扫关注
    公众号

[go]并发编程(go关键字和select关键字)

原作者: [db:作者] 来自: [db:来源] 收藏 邀请

其实和if switch for等循环结构一样. go 是一种控制结构, 控制协程的启动等生命周期.

并发基础

程序与进程
并发与并行

启动多个协程

// 同步代码
func hello() {
    time.Sleep(time.Second/3)
	fmt.Println("Hello Goroutine!")
}
func main() {
	hello()
	fmt.Println("main goroutine done!")
}
//异步
func hello() {
    time.Sleep(time.Second/3)
	fmt.Println("Hello Goroutine!")
}
func main() {
	go hello()                          // 启动另外一个goroutine去执行hello函数
	fmt.Println("main goroutine done!") //不会被输出
}

//main结束,程序即运行结束
func main() {
	go hello() // 启动另外一个goroutine去执行hello函数
	fmt.Println("main goroutine done!")
    time.Sleep(time.Second)
}
  • 协程同步
- runtime包里的函数

// runtime.GOMAXPROCS() 设置核心数

- 用一个core执行
func main() {
	runtime.GOMAXPROCS(1)
	go func() {
		for {
			fmt.Print(1)

		}
	}()
	go func() {
		for {
			fmt.Print(2)
		}
	}()
	time.Sleep(time.Second * 1)
}
//打印的1 2 成块的


- 用2个core执行
func main() {
	runtime.GOMAXPROCS(2)
	go func() {
		for {
			fmt.Print(1)

		}
	}()
	go func() {
		for {
			fmt.Print(2)
		}
	}()
	time.Sleep(time.Second * 1)
}
//打印的1 2交替较明显
// runtime.Gosched() //出让当前执行机会, 等下次又机会时继续往下执行
func main() {
	runtime.GOMAXPROCS(1)
	go func() {
		for {
			fmt.Print("m")

		}
	}()
	go func() {
		for {
		    runtime.Gosched()
			fmt.Print("g")
		}
	}()
	time.Sleep(time.Second)
}
- runtime.Goexit()结束本go程
- return结束当前函数
// return结束当前函数
func test() {
	println(1)
	return
	println(2)
}

func main() {
	test()
	println("main")
}
//1
//main
//runtime.Goexit结束当前go程
func test() {
	println(1)
	runtime.Goexit()
	println(2)
}

func main() {
	test()
	println("main")
}
// 1
// fatal error: no goroutines (main called runtime.Goexit) - deadlock!
// defer: 当函数结束时被调用

func main() {
	defer println("test end 1") //栈结构:一个桶 后进先出
	defer println("test end 2")
	println("testing")
}
//testing
//test end 2
//test end 1
// return后的defer不会被注册
func main() {
	defer println("1")
	println("main")
	return
	defer println("2")
}
//main
//1
// runtime.Goexit后的defer不会被注册
func main() {
	defer println("1")
	println("main")
	runtime.Goexit()
	defer println("2")
}
//main
//1
//fatal error: no goroutines (main called runtime.Goexit) - deadlock!
- 小结: 
    runtime.Goexit()和return后的defer都不会被注册, 
    只有代码能执行到,defer才会被注册

func main() {
    go func() {
        defer fmt.Println("aaaaaaaaaaaaa")
        runtime.Goexit()
        defer fmt.Println("bbbbbbbbbb")
    }()
    time.Sleep(time.Second * 1)
}
//aaaaaaaaaaaaa


func main() {
    go func() {
        defer fmt.Println("aaaaaaaaaaaaa")
        return
        defer fmt.Println("bbbbbbbbbb")
    }()
    time.Sleep(time.Second * 1)
}
//aaaaaaaaaaaaa
// 带go
func test() {
    defer fmt.Println("ccccccccccc")
    runtime.Goexit()
    defer fmt.Println("dddddddddddddd")
}

func main() {
    go func() {
        defer fmt.Println("aaaaaaaaaaaaa")
        go test()
        defer fmt.Println("bbbbbbbbbb")
    }()
    time.Sleep(time.Second)
}
//bbbbbbbbbb
//aaaaaaaaaaaaa
//ccccccccccc
//不带go
func test() {
    defer fmt.Println("ccccccccccc")
    runtime.Goexit()
    defer fmt.Println("dddddddddddddd")
}

func main() {
    go func() {
        defer fmt.Println("aaaaaaaaaaaaa")
        test()
        defer fmt.Println("bbbbbbbbbb")
    }()
    time.Sleep(time.Second)
}
//ccccccccccc
//aaaaaaaaaaaaa

定时器

[go]time包

睡一秒

//方法1:
func main() {
    time.Sleep(time.Second)
}

//方法2:
func main() {
	fmt.Println(<-time.NewTimer(time.Second).C))
}

//方法3:
func main() {
    fmt.Println(<-time.After(time.Second))
}

// 定时回调(setTimeout)
time.AfterFunc(time.Second, func() {
    println("after 1s cb")
})
time.Sleep(time.Second*3)
//周期定时器(setInterval)
func main() {
	tickTimer := time.NewTicker(time.Second)
	for {
		fmt.Println(<-tickTimer.C)
	}
}

select - 管理多个chan

select是一种控制结构, 和if switch for控制结构一样, 用于控制管理多个管道

Go并发编程—select的使用

select可以同时监控多个通道的情况,只处理未阻塞的case。
每个case必须是一个chan的io操作

select会阻塞在多个channel上,对多个channel的读/写事件进行监控。
case中的channel的事件包括:
    读取的时候,
    channel被close,或
    写入时channel没有空间。
// 多个chan,随机选一个执行. 对多个chanel调度机会基本是均等的

当通道为nil时,对应的case永远为阻塞,无论读写。
    特殊关注:普通情况下,对nil的通道写操作是要panic的。
func main() {
    c1 := make(chan interface{}); close(c1)
    c2 := make(chan interface{}); close(c2)
    c3 := make(chan interface{}); close(c3)

    var c1Count, c2Count, c3Count int
    for i := 1000; i >= 0; i-- {
        select {
        case <-c1:
            c1Count++
        case <-c2:
            c2Count++
        case <-c3:
            c3Count++
        }
    }
    fmt.Printf("c1Count: %d\nc2Count: %d\nc3Count: %d\n", c1Count, c2Count, c3Count)
}
//select管理多个管道
func main() {
	ch := make(chan int, 1) //仅限于缓冲通道
	for i := 0; i < 10; i++ {
		select {
		case x := <-ch:
			fmt.Println(x)
		case ch <- i:
		}
	}
}
// select管理多个管道
func main() {
	ch := make(chan int)
	done := make(chan bool)
	go func() {
		for i := 0; i < 10; i++ {
			ch <- i
			time.Sleep(time.Second / 3)
		}
		close(ch)
		done <- true
	}()
	for {
		select {
		case <-done:
			fmt.Println("Done!")
			return
		case t := <-ch:
			fmt.Println("ch value: ", t)
		}
	}
}




// 没有任何channel准备好,处理默认事件
func main() {
	start := time.Now()
	var c1, c2 <-chan int
	select {
	case <-c1:
	case <-c2:

	default:
		fmt.Printf("In default after %v\n\n", time.Since(start))
	}
}

// 没有任何channel准备好,处理超时

func main() {
    var c <-chan int

    for {
        select {
        case <-c:
        case <-time.After(1 * time.Second):
            fmt.Println("Timed out.Do something.")
        }
    }
}
2. 退出

select {
    case <- done:
        cleanUp()
        return
    default:
}
3.判断channel是否阻塞
func main() {
	var ch chan int = make(chan int, 5)
	for {
		select {
		case ch <- 1:
			fmt.Println("add success")
		default: // channel满了
			fmt.Println("chan is full")
            return
		}
	}
}
4.检测chanel关闭事件
func main() {
    start := time.Now()
    c := make(chan interface{})

    go func() {
        time.Sleep(2*time.Second)
        close(c)
    }()

    fmt.Println("Blocking on read...")
    select {
    case <-c:
        fmt.Printf("Unblocked %v later.\n", time.Since(start))
    }
}

// select{} 永久阻塞, 直到有信号中断.
func main() {
	go func() {
		for {
			fmt.Println(time.Now())
			time.Sleep(time.Second / 3)
		}
	}()

	select {}
}

鲜花

握手

雷人

路过

鸡蛋
该文章已有0人参与评论

请发表评论

全部评论

专题导读
上一篇:
《Go学习笔记 . 雨痕》反射发布时间:2022-07-10
下一篇:
GO语言为结构体排序发布时间:2022-07-10
热门推荐
热门话题
阅读排行榜

扫描微信二维码

查看手机版网站

随时了解更新最新资讯

139-2527-9053

在线客服(服务时间 9:00~18:00)

在线QQ客服
地址:深圳市南山区西丽大学城创智工业园
电邮:jeky_zhao#qq.com
移动电话:139-2527-9053

Powered by 互联科技 X3.4© 2001-2213 极客世界.|Sitemap