Golang,协程,channel,无缓存channel,死锁,select,代码案例

Golang,协程,channel,无缓存channel,死锁,select,代码案例channelchann 不同的翻译资料叫法不一样 常见的叫法 管道 信道 通道 channel 是进程内的通信方式 每个 channel 只能传递一个类型的值 这个类型需要在声明 channel 时指定 channel 在 Golang 中

大家好,欢迎来到IT知识分享网。

channel

channel

channel不同的翻译资料叫法不一样,常见的叫法:管道,信道,通道,channel是进程内的通信方式,每个channel只能传递一个类型的值,这个类型需要在声明channel时指定

channel在Golang中主要有2个作用:同步、通信。

var 名称 chan 类型 // 读写 var 名称 chan <- 类型 // 只写 var 名称 <- chan 类型 // 只读 名称 := make(chan int) // 无缓存channel 名称 := make(chan int, 0) // 无缓存channel 名称 := make(chan int, 100) // 有缓存channel

案例

package main import ( "fmt" "time" ) func main() { // channel // demo44_1() // demo44_2() // 协程之间的通信 // demo44_3() // 数据很多,用range接收 // demo44_4() // channel是安全的,多个goroutine同时操作时,同一时间只能由一个goroutine存取数据 demo44_5() } func demo44_5() { ch := make(chan int) for i := 1; i < 5; i++ { go func(j int) { fmt.Println(j, "开始") ch <- j fmt.Println(j, "结束") }(i) } for j := 1; j < 5; j++ { time.Sleep(2 * time.Second) num := <-ch fmt.Println("取出数据:", num) } } func demo44_4() { ch1 := make(chan string) ch2 := make(chan int) go func() { for i := 97; i < 97+26; i++ { ch1 <- fmt.Sprintf("%c", i) } ch2 <- 1 }() go func() { // 代码是阻塞的(range) for c := range ch1 { fmt.Printf("取出:%s \n", c) } }() // 同步等待 <-ch2 // time.Sleep(1e9) fmt.Println("demo44_4() end") } // 子协程之间的同步 func demo44_3() { ch1 := make(chan string) ch2 := make(chan int) go func() { ch1 <- "传送数据" ch2 <- 1 }() go func() { s1 := <-ch1 fmt.Println("取出数据:", s1) ch2 <- 1 }() // 同步等待 <-ch2 <-ch2 // time.Sleep(1e9) fmt.Println("demo44_3() end") } // 主协程和子协程之间的同步 func demo44_2() { ch := make(chan int) go func() { fmt.Println("执行") // fmt.Println("结束") ch <- 999 }() a := <-ch fmt.Println(a) fmt.Println("demo44_2() end") } func demo44_1() { ch := make(chan int) go func() { fmt.Println("进入 goroutine") close(ch) }() c, d := <-ch fmt.Println(c, d) fmt.Println("demo44_1() end.") }

死锁和有缓存通道

死锁

goroutine中向无缓存channel添加内容或在主goroutine中向channel添加内容,且添加内容的个数已经大于channel缓存个数就会产生死锁。

死锁,在城中多个进程由于相互竞争资源而产生的阻塞(等待)状态,这种状态一直保持下去,此时称这个线程是死锁状态。

案例

package main import ( "fmt" "time" ) func main() { // 死锁和有缓存通道 // demo43_1() // demo43_2() // demo43_3() demo43_4() } func demo43_4() { ch := make(chan int, 3) ch <- 1 fmt.Println(<-ch) ch <- 2 fmt.Println(<-ch) ch <- 3 ch <- 4 fmt.Println(len(ch)) fmt.Println(cap(ch)) } // deadlock func demo43_3() { ch := make(chan int, 3) ch <- 1 ch <- 2 ch <- 3 ch <- 4 // 慈航出现死锁,超过缓存大小数量 } // 不会产生死锁 func demo43_2() { ch := make(chan int) // 子协程中阻塞 不影响主协程 go func() { ch <- 1 fmt.Println("执行goroutine") }() time.Sleep(time.Second) fmt.Println("demo43_2() end.") } // 死锁 func demo43_1() { ch := make(chan int) ch <- 1 }

select

select

select和switch结构特别像,select中case的条件只能是I/O。

select执行过程

每个case必须是一个IO操作;哪个case可以执行就执行哪个;所有case都不能执行时,执行default;所有case都不能执行,且没有default,将会阻塞。

案例

package main import ( "fmt" "runtime" "time" ) func main() { // select // demo42_1() // demo42_2() demo42_3() } // select和for循环结合使用 func demo42_3() { ch := make(chan int) for i := 0; i <= 5; i++ { go func(arg int) { ch <- arg }(i) } for { select { case c := <-ch: fmt.Println("取出数据", c) default: time.Sleep(time.Second) // 没有default会出现死锁 fmt.Println("default") } } fmt.Println("demo42_3() end") } // select和for循环结合使用 func demo42_2() { ch := make(chan int) for i := 0; i <= 5; i++ { go func(arg int) { ch <- arg }(i) } for i := 0; i <= 5; i++ { select { case c := <-ch: fmt.Println("取出数据", c) default: // 没有default会出现死锁 fmt.Println("default") } } fmt.Println("demo42_2() end") } func demo42_1() { runtime.GOMAXPROCS(1) ch1 := make(chan int, 1) ch2 := make(chan string, 1) ch1 <- 1 ch2 <- "hello" select { case value := <-ch1: fmt.Println(value) case value := <-ch2: fmt.Println(value) default: fmt.Println("default") } }

免责声明:本站所有文章内容,图片,视频等均是来源于用户投稿和互联网及文摘转载整编而成,不代表本站观点,不承担相关法律责任。其著作权各归其原作者或其出版社所有。如发现本站有涉嫌抄袭侵权/违法违规的内容,侵犯到您的权益,请在线联系站长,一经查实,本站将立刻删除。 本文来自网络,若有侵权,请联系删除,如若转载,请注明出处:https://yundeesoft.com/109015.html

(0)
上一篇 2024-11-15 16:26
下一篇 2024-08-21 22:33

相关推荐

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注

关注微信