/*
* A:向一个channel中不断发送数字
* B:从channel中取值,然后将值变成平方
* main: 从B中接收值进行打印
*
* */
/***
* // channel 练习
* func main() {
* ch1 := make(chan int)
* ch2 := make(chan int)
* // 开启goroutine将0~100的数发送到ch1中
* go func() {
* for i := 0; i < 100; i++ {
* ch1 <- i
* }
* close(ch1)* }()
* // 开启goroutine从ch1中接收值,并将该值的平方发送到ch2中
* go func() {
* for {
* i, ok := <-ch1 // 通道关闭后再取值ok=false
* if !ok {
* break
* }
* ch2 <- i * i
* }
* close(ch2)* }()
* // 在主goroutine中从ch2中接收值打印
* for i := range ch2 { // 通道关闭后会退出for range循环
* fmt.Println(i)* }
* }
*/
/***
*
package main
import(
"fmt"
"sync"
)
var chan1 = make(chan int ,10)
var chan2 = make(chan int,10)
var wg sync.WaitGroup
func main(){
wg.Add(2)
go A()
go B()
wg.Wait()
for i := range chan2 { // 通道关闭后会退出for range循环
fmt.Println(i)
}
}
func A(){
defer wg.Done()
for i:=0;i<10;i++{
chan1 <- i
}
//开局就会被阻塞
close(chan1)
}
func B(){
defer wg.Done()
for{
i,ok:=<-chan1
if!ok{
break
}
i = i*i
chan2<-i
}
//打印完会被阻塞
close(chan2)
}
package main
import(
"fmt"
)
var chan1 = make(chan int ,10)
func main(){
close(chan1)
i:= <-chan1
fmt.Println(i)//0
}
package main
import(
"fmt"
)
var chan1 = make(chan int ,10)
func main(){
for i:=0;i<10;i++{
chan1<-i
fmt.Printf("将%d,存入channel中\n",i)
}
for ch := range chan1 { // 通道关闭后会退出for range循环
fmt.Println(ch)
}
}
*/
/**
channel 总共只有三总操作,发送 接收 关闭
发送和接收都是适用<-进行操作的
关闭通道:
什么时候进行关闭:通知接收方,所有的数据都已经发送完毕之后需要关闭通道,通道不是一定需要关闭的,跟io不一致
通道是可以被垃圾回收的
关闭通道的注意事项:
关闭一个已经关闭的通道会panic
接收一个关闭的通道时,会取完里面所有的值,为空就返回
接收一个关闭且没有值的通道,会取到其类型对应的零值
像一个关闭的channel发送值会panic
无缓冲的channel,只发会阻塞,只拿也会阻塞,必须同时有拿才不会阻塞
channel中取值
package main
import(
"fmt"
)
var ch1 chan int
// channel 的取值
func main() {
ch1 = make(chan int,10)
for i:=1;i<11;i++{
ch1<-i
}
//循环取值的话,必须得关闭,否则会报错
//close(ch1)
//getByFor()
//getByRange()
getBySelect()
}
func getByFor(){
for{
i,ok := <-ch1
if !ok{
break
}
fmt.Println(i)
}
}
func getByRange(){
for i := range ch1{
fmt.Printf("使用range进行取值:%d\n",i)
}
}
func getBySelect(){
for i:=0;i<11;i++{
select{
case x:= <-ch1:
fmt.Printf("使用select进行取值:%d\n",x)
default:
fmt.Printf("使用select进行取默认值\n")
}
}
}
//从空channel中取值会死锁,但是从关闭的channel中取值,如果没有的话就是零值
package main
import(
"fmt"
)
// channel 的取值
func main() {
ch1 := make(chan int,10)
fmt.Println(ch1)
x := <-ch1
fmt.Println(x)
}
加close的原因:如果不关闭,取值取不到就会死锁,
并发和锁
使用10个线程去卖票
package main
import(
"fmt"
"sync"
)
var ticket int = 10
var wg sync.WaitGroup
var lock sync.Mutex
// channel 练习
func main() {
wg.Add(2)
for i:=0;i<2;i++{
go saleTicket()
}
wg.Wait()
}
func saleTicket(){
defer wg.Done()
for{
lock.Lock()
if ticket<=0{
break
}
fmt.Printf("卖出第%v张票\n",ticket)
ticket--
lock.Unlock()
}
}
var (
x int64
wg sync.WaitGroup
lock sync.Mutex
rwlock sync.RWMutex
)
func write() {
// lock.Lock() // 加互斥锁
rwlock.Lock() // 加写锁
x = x + 1
time.Sleep(10 * time.Millisecond) // 假设读操作耗时10毫秒
rwlock.Unlock() // 解写锁
// lock.Unlock() // 解互斥锁
wg.Done()
}
func read() {
// lock.Lock() // 加互斥锁
rwlock.RLock() // 加读锁
time.Sleep(time.Millisecond) // 假设读操作耗时1毫秒
rwlock.RUnlock() // 解读锁
// lock.Unlock() // 解互斥锁
wg.Done()
}
func main() {
start := time.Now()
for i := 0; i < 10; i++ {
wg.Add(1)
go write()
}
for i := 0; i < 1000; i++ {
wg.Add(1)
go read()
}
wg.Wait()
end := time.Now()
fmt.Println(end.Sub(start))
}
*/