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

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

内容简介:这里不会报错而是会返回  接收成功: 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秒,最后才有了这样的结果

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

查看所有标签

猜你喜欢:

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

算法笔记

算法笔记

胡凡、曾磊 / 机械工业出版社 / 2016-7 / 65

这是一本零基础就能读懂的算法书籍,读者不需要因为自己没有语言基础而畏惧。书籍的第2章便是一个C语言的入门教程,内容非常易懂,并且十分实用,阅读完这章就可以对本书需要的C语言基础有一个较好的掌握。 本书已经覆盖了大部分基础经典算法,不仅可以作为考研机试和PAT的学习教材,对其他的一些算法考试(例如CCF的CSP考试)或者考研初试的数据结构科目的学习和理解也很有帮助,甚至仅仅想学习经典算法的读者......一起来看看 《算法笔记》 这本书的介绍吧!

URL 编码/解码
URL 编码/解码

URL 编码/解码

XML、JSON 在线转换
XML、JSON 在线转换

在线XML、JSON转换工具

正则表达式在线测试
正则表达式在线测试

正则表达式在线测试