GO语言学习-并发

定义

并发(concurrency):逻辑上具备同时处理多个任务的能力。
并行(parallesim)不同于并发,物理上的同一时刻,相当于并发设计的理想执行模式。

在函数调用前添加 go关键字即可创建并发任务

a := 100

go func(x, y int){
   //time.Sleep(time.Second)
   println("go:",x,y) //立即计算并复制参数
}(a, counter())
a = a + 66
println("main:",a,counter())

输出:
main: 166 2
go: 100 1

wait阻塞

等待并发任务结束
1.通道channel
2.sync.WaitGroup
设定计数器,让goroutine在退出前递减,在归零时解除阻塞。

GOMAXPROCS

修改运行时的线程数量
runtime.GOMAXPROCS(),参数<1时,返回当前设置值,不作调整

实现Local Storage

goroutine没有局部存储,无法获取编号,返回值也会被抛弃,需自己写方法实现
不适用waitgroup时:

//var wg sync.WaitGroup
var gs [5]struct { //用于实现类似TLS的功能
   id int       //编号
   result int    //返回值
}
for i := 0;i < len(gs) ;i++ {
   //wg.Add(1)
   go func (id int){  //使用参数避免闭包求值延迟
      //defer wg.Done()

      gs[id].id = id
      gs[id].result = (id + 1)* 100
   }(i)
}
//wg.Wait()
fmt.Printf("%+v\n",gs)

输出为:
在这里插入图片描述
程序并发,未等到多个任务结束时就退出进程

    var wg sync.WaitGroup
   var gs [5]struct { //用于实现类似TLS的功能
      id int       //编号
      result int    //返回值
   }
   for i := 0;i < len(gs) ;i++ {
      wg.Add(1)
      go func (id int){  //使用参数避免闭包求值延迟
         defer wg.Done()

         gs[id].id = id
         gs[id].result = (id + 1)* 100
      }(i)
   }
   wg.Wait()
   fmt.Printf("%+v\n",gs)
}

期望输出:在这里插入图片描述

Goexit

goexit立即终止当前任务;
不会影响其他并发任务,不会引发panic。
在main.main中调用Goexit,他会等待其他任务结束,然后让进程直接崩溃。
(听起来很任性hhh)

通道channel

底层看来,通道相当于一个队列。
同步模式:发送和接收方配对,直接将数据赋值给对方;配对失败时,进入等待队列,知道另一方出现后唤醒。
必须有配对操作的goroutine出现,否则阻塞。

异步模式:抢夺数据缓冲槽,发送方需要写入,接收方需要缓冲数据可读。
异步通道有助于提升性能,减少排队阻塞。

此外,通道还被用作事件通知。

//信号通知
done := make(chan struct{})    //结束事件
//chan struct{}:不能被写入任何数据,不占用任何内存。
//必须通过close进行关闭操作才能输出
c := make(chan string)    //数据传输通道

go func(){
   s := <-c            //接收消息
   println(s)
   close(done)             //关闭消息,作为结束通知
}()

c <- "hello!"           //发送消息
println(c)       //输出地址?
<-done              //阻塞,直到有数据或通道关闭

//异步
c1 := make(chan int,3) //创建带有3个缓冲槽的异步通道
c1 <- 1
c1 <- 2
println(<-c1)
println(<-c1)
//println(<-c1)          //会报错:fatal error: all goroutines are asleep - deadlock!

通道变量本身就是指针可以判断是否为同一对象或者nil。

可用caplen函数判断同步/异步,同步通道两者都返回0.
cap:返回已缓冲数量
len:返回缓冲区大小

println("c:",len(c),cap(c))
println("c1:",len(c1), cap(c1))

输出:
在这里插入图片描述

var wg sync.WaitGroup
ready := make(chan struct{})

for i := 0 ; i < 3 ;i++ {
   wg.Add(1)
   go func(id int) {
      defer wg.Done()

      println(id, ":ready!")
      <-ready
      println(id, ":running!")
   }(i)
}
time.Sleep(time.Second)
println("Ready?Go!")

close(ready)   //peng!

wg.Wait()

输出:并发事件不保证输出顺序(?)在这里插入图片描述
已关闭通道:
发送数据->引发panic
接收数据->返回已缓冲数据或零值
nil通道:
收发都会阻塞

单向通道

使用类型转换获取单向通道,并分别赋予操作双方

//单向操作
var wg sync.WaitGroup
wg.Add(2)     //收 发,参数为2
c1way := make(chan int)
var send chan<- int = c1way
var recv <-chan int = c1way

go func() {
   defer wg.Done()
   for x := range recv {
      println(x)
   }
}()
go func(){
   defer wg.Done()
   defer close(c1way)

   for i := 5; i < 9 ; i++{
      send <- i
   }
}()
wg.Wait()
//禁止逆向操作
//<- send     //invalid operation: <-send (receive from send-only type chan<- int)
//recv <- 1       //invalid operation: recv <- 1 (send to receive-only type <-chan int)

//close(recv)     //invalid operation: close(recv) (cannot close receive-only channel)
//单向不可逆
//c2ways := (chan int)(recv)   //cannot convert recv (type <-chan int) to type chan int
//c2ways = (chan int)(send)       //cannot convert send (type chan<- int) to type chan int

输出结果:在这里插入图片描述
通道还可以实现信号量机制
以及同步。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值