Go的学习旅程8:系统研究goroute

栏目: Go · 发布时间: 6年前

内容简介:这里不会报错而是会返回  接收成功: 2

学习go,主要是为了后期数据的并发处理,所以今天重新学习和细究了一遍 go 的并发和并发间的通信

1.协程的作用域

package main

import (
   "fmt"
)

func test(a string){
   fmt.Println("我是:",a)
}


func main() {
   fmt.Println(111111)
   go test("并发")
   test("普通")
}

执行以下的代码,等到的结果是:

Go的学习旅程8:系统研究goroute

  • 其实这里面有一个问题就是,系统中每一个进程最少是有一个线程的,而协程也是作用在进程内的,而go多进程的实现,就是利用轻量级的协程来实现的; (协程其实就是异步+回调的方式) 所以当程序全部运行结束的时候,协程还没有走完,最终没有输出结果.
  • 主函数返回时,所有的goroutine都会被直接打断,程序退出。除了从主函数退出或者直接终止程序之外,没有其它的编程方法能够让一个goroutine来打断另一个的执行,但是之后可以看到一种方式来实现这个目的,通过goroutine之间的通信来让一个goroutine请求其它的goroutine,并让被请求的goroutine自行结束执行。

在明白为什么程序没有输出结果以后,我们也找到了相应的对策:

package main

import (
   "fmt"
   "time"
)

func test(a string){
   fmt.Println("我是:",a)
}


func main() {
   fmt.Println(111111)
   go test("并发")
   test("普通")
   time.Sleep(1)
}

time.Sleep(1) 程序沉睡1s,让我们的协程有充分的时间去做异步回调等等...

输出的结果为:

Go的学习旅程8:系统研究goroute

2.协程的使用

package main

import (
   "fmt"
   "time"
)

func loop(i int,b string)  {
   fmt.Println("我是:",b,i)
}

func main() {
   for i:=0;i<10 ;i++  {
      loop(i,"单线程")
   }
   for i:=0;i<10 ;i++  {
      go loop(i,"多线程")
   }
   time.Sleep(1)
}

结果为: 

Go的学习旅程8:系统研究goroute

  • 这里我们可以注意到,首先第一个for是单线程的,所以就是按顺序执行,而下一个for使用到了goroute,基本可以认为是谁快谁输出,所以执行的顺序是无序的;

3.Channels的基本语法

无缓存的错误写法:

package main

import "fmt"

func main() {
   c:=make(chan int)
   c<-2
   fmt.Println("接收成功:",<-c)
}

这里是会报错的,本来没有消耗,以及阻塞了,再加一个便会报错

有缓存的错误写法:

package main

import "fmt"

func main() {
   c:=make(chan int,1)
   c<-2
   fmt.Println("接收成功:",<-c)
}

这里不会报错而是会返回  接收成功: 2

4.Channels间的通讯

package main

import (
   "time"
   "fmt"
)

func write(c chan int) {
   for i := 0; i < 10; i++ {
      c <- i
   }
}

func read(c chan int) {
   for {
      fmt.Println("go:",<-c)
      time.Sleep(1)
   }
}
func readgo(c chan int)  {
   for v := range c{
      fmt.Println("并发通信:",v)
   }
}

func main() {
   c := make(chan int)
   go write(c)
   go read(c)
   go readgo(c)
   time.Sleep(2)
}

结果返回:

Go的学习旅程8:系统研究goroute

  • 在上面的例子中我们可以看到,channels在goroute中的通信是同时进行的, (如果是单线程的顺序执行进行,go:1是不可能在中间的) 也就是说go write(c)/go read(c)/go readgo(c)这3个函数是同时进行的,有读有写才不会让goroute阻塞

5.Channels的关闭

package main

import "fmt"

func main() {
   a := make(chan int, 15)
   for i := 0; i < 10; i++ {
      a <- i
   }

   close(a)

   for {
      if v, ok := <-a; !ok {
         fmt.Println("不存在")
         break
      } else {
         fmt.Println(v)
      }
   }

}

结果返回:

Go的学习旅程8:系统研究goroute

  • 例子中的 channels是a,有本来的15个缓存位置,但是只是用了10个,如何没有关闭,系统则会报错
  • 记住应该在生产者的地方关闭 channel,而不是消费的地方去关闭它,这样容易引起 panic

6.利用Channels的通信关闭goroute

package main

import (
   "fmt"
   "strconv"
)

func add(c chan string, i int) {

   fmt.Println("我的编号是:", i)
   c <- "天王盖地虎"+strconv.Itoa(i)
}

func main() {
   c := make(chan string)
   for i := 0; i < 10; i++ {
      go add(c, i)
   }
   for i := 0; i < 10; i++ {
      <-c
   }
}

结果返回:

                     Go的学习旅程8:系统研究goroute

  • 代码的逻辑是,先创建了10个线程,并在管道中建立通信,完后才会提取c中的数据,最后提取完后,结束进程.
  • 代码分析:   go add(c,i)在执行的时候是异步的,所以是不会占用主线程,这时channels中会形成阻塞,当执行<-c的处理时又会开始消耗channels,此时的for是占用线程的,当全部执行完for循环时,意味着go add(c,i)也就全部执行结束,    最终提取完成,结束进程


  • 假设1:
  • 代码先提取channels中的数据,后添加,这样的运行结果是panic的,原因是 channels的c中一直没有数据,所以提取会直接报错
  • for i := 0; i < 10; i++ {
       <-c
    }
    for i := 0; i < 10; i++ {
       go add(c, i)
    }

7.多个Channels的利用

package main

import (
   "fmt"
   "time"
)

func add(job chan int, c chan bool, i int) {
   for v := range job {
      fmt.Println("序号:", i, "我的工作是:", v)
      time.Sleep(time.Second)
      c <- true
   }

}

func main() {
   c := make(chan bool)
   job := make(chan int,10)
   for i := 0; i < 3; i++ {
      go add(job, c, i)
   }
   for i := 0; i < 10; i++ {
      job<-i
   }
   close(job)
   for i := 0; i < 10; i++ {
      <-c
   }
}

结果返回:

Go的学习旅程8:系统研究goroute

  • 这里面需要注意的是:在add()这个函数里面有time.Sleep(time.Second)(沉睡一秒)的条件,所以我们可以更加的直观查看代码的执行;
  • 代码分析:创建c和job两个管道, 创建3条线程 并发执行add()函数,job里面插入数据后关闭,最后读取管道c的数据,最终结束
  • add()函数中创建了10条job信息,而线程只有3个,执行完一次只能是程序沉睡1秒,最后才有了这样的结果

以上就是本文的全部内容,希望本文的内容对大家的学习或者工作能带来一定的帮助,也希望大家多多支持 码农网

查看所有标签

猜你喜欢:

本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们

Making Things See

Making Things See

Greg Borenstein / Make / 2012-2-3 / USD 39.99

Welcome to the Vision Revolution. With Microsoft's Kinect leading the way, you can now use 3D computer vision technology to build digital 3D models of people and objects that you can manipulate with g......一起来看看 《Making Things See》 这本书的介绍吧!

随机密码生成器
随机密码生成器

多种字符组合密码

MD5 加密
MD5 加密

MD5 加密工具

SHA 加密
SHA 加密

SHA 加密工具