玩转Go语言之并发初体验

224 阅读3分钟
下篇更精彩!

1.明白几个概念:

串行:
    同一时刻,只有一条指令,在一个cpu上执行,后面的指令需要等到前面的指令完成之后才能执行
也就是说,程序中接口请求是一个执行完成之后,紧接着执行下一个

并行:
    同一时刻,有多条指令,在多个cpu上执行,也就是说,多个接口同时请求服务器获取数据

并发:
    同一时刻,在一条指令,在一个cpu上执行,但是cpu可以快速的在多条指令之间来回切换执行.

程序:
    编编译之后保存在磁盘上的二进制文件,会占用磁盘空间,但不会占用系统资源.

进程:
    程序在操作系统中一次执行过程,比如打开某个桌面应用,系统会开启一个进程,同一个程序可以打开多次,也就是说可以出现多个进程,进程与进程之间互不影响

线程:
    线程是进程中的一个执行实例,也就是说进程开启的同时会自动创建一个线程,主线程,进程中除了主线程,可以创建多个线程,也就是我们常说的多线程

协程:
    协程是轻量级的线程,一个线程中可以有任意多个协程,但某一时刻只能有一个协程在运行.

2.go中怎么开启协程:

func say()  {
   for i := 0; i < 20; i++{
      fmt.Println("正在----说话")
   }
}

func eat()  {
   for i := 0; i < 20; i++{
      fmt.Println("正在++++++吃饭")
   }
}

func main() {

   go say()
   go eat()

   // 一旦主线程结束了, 那么程序就关闭了, 那么进程就不见了, 那么协程就不会被执行了
   for{
      ;
   }
}

3.怎么退出协程

func say()  {
   for i := 0; i < 20; i++{

      fmt.Println("正在----说话")
      if i== 5 {
         runtime.Goexit()
      }

   }
}

func eat()  {
   for i := 0; i < 20; i++{
      fmt.Println("正在++++++吃饭")
   }
}

func main() {

   go say()
   go eat()

   // 一旦主线程结束了, 那么程序就关闭了, 那么进程就不见了, 那么协程就不会被执行了
   for{
      ;
   }
}

4.如果同时开启多个协程,并且协程访问同一资源,那怎么保证不出错

需求1: 定义个打印的函数, 可以逐个的打印传入字符串的每个字符,在两个协程中调用这个好方法, 并且还要保持输出的内容有序的
//创建一个互斥锁
var lock = sync.Mutex{}

func printChar(str string)  {

   //加锁,让别的协程无法访问
   lock.Lock()

   for _, ch := range str{
      fmt.Printf("%c",ch)

      time.Sleep(time.Microsecond * 300)
   }

   //解锁,让别的协程能访问
   lock.Unlock()
}

func people1()  {
   printChar("hello")
}

func people2()  {
   printChar("world")
}

func main() {

   go people1()

   go people2()

   // 一旦主线程结束了, 那么程序就关闭了, 那么进程就不见了, 那么协程就不会被执行了
   for{
      ;
   }
}
需求2:定义一个生产函数写入数据到数组,同时一个消费函数输出数组的数据,保证先生产,后消费
var buff [10] int
var lock = sync.Mutex{}

func producer()  {

   lock.Lock()

   //种随机种子
   rand.Seed(time.Now().UnixNano())
   for i := 0; i < 10; i++ {

      num := rand.Intn(100)
      fmt.Println("生产者生产了", num)

      //添加随机数
      buff[i] = num

      time.Sleep(time.Millisecond * 300)
   }

   lock.Unlock()
}

func consumer()  {

   lock.Lock()

   for i:=0; i<10;i++  {
      num := buff[i]
      fmt.Println("-------消费者消费到了", num)

      time.Sleep(time.Millisecond * 300)
   }

   lock.Unlock()
}

func main() {

   go producer()

   go consumer()

   // 一旦主线程结束了, 那么程序就关闭了, 那么进程就不见了, 那么协程就不会被执行了
   for{
      ;
   }
}

注意点: 看上去通过给生产者以及消费者同时加锁就能解决, 只有生产完了才能消费         但是取决于谁想执行加锁操作, 所以不完美.