春招打卡|多协程顺序打印

382 阅读2分钟

Offer 驾到,掘友接招!我正在参与2022春招打卡活动,点击查看活动详情

一、题目描述

让两个goroutine顺序打印数据。

二、思路分析

  1. 在其他语言中,相当于让两个线程交替打印数据,在go语言中,则是使用协程即goroutine。
  2. 启动三个channel,分别存放打印数据A令牌,打印数据B令牌,以及任务完成通道,用于主线程等待协程完成任务。
  3. 通道内存空结构体,因为空结构体不占用内存,printDog协程,首先从cat通道接收数据,如果cat通道无数据,则printCat协程未完成打印操作,当前printDog协程阻塞。如果cat通道有数据,则PrintDog协程完成打印操作,并向dog 通道放数据,通知printCat协程进行操作。
  4. 打印1和2与此类似,开启两个通道分别用于通知其协程已完成操作。
  5. main函数中,向cat通道发送数据,通知dog进行打印,最后cat协程完成任务,向done通知任务已完成,main函数从done接收数据,取消阻塞。

三、AC 代码

顺序打印cat,dog

package main

import (
	"fmt"
	"sync"
)

var dog = make(chan struct{}, 1)
var cat = make(chan struct{}, 1)
var done = make(chan struct{}, 1)

var wg sync.WaitGroup

func printDog() {
	wg.Add(1)
	defer wg.Done()
	defer close(dog)
	for i := 0; i < 4; i++ {
		<-cat
		fmt.Println("dog")
		dog <- struct{}{}
	}
}
func printCat() {
	wg.Add(1)
	defer wg.Done()
	defer close(cat)
	for i := 0; i < 4; i++ {
		<-dog
		fmt.Println("cat")
		cat <- struct{}{}
	}
	done <- struct{}{}
}

func main() {
	cat <- struct{}{}
	go printDog()
	go printCat()
	wg.Wait()
	<-done

}

顺序打印1与2

package main

import "fmt"

var one = make(chan struct{}, 1)
var two = make(chan struct{}, 1)
var done = make(chan struct{})

func PrintOne() {
	defer close(one)
	for i := 0; i < 10; i++ {
		//必须由缓冲,不然two被拿走,才可以向下执行
		<-two
		fmt.Println("1")
		one <- struct{}{}
	}
}
func PrintTwo() {
	defer close(two)
	for i := 0; i < 10; i++ {
		<-one
		fmt.Println("2")
		two <- struct{}{}
	}
	done <- struct{}{}
}
func main() {
	defer close(done)
	two <- struct{}{}
	go PrintOne()
	go PrintTwo()
	<-done
}

四、总结

顺序打印数据是多线程(多协程)的常见题目,有多种实现方法,go由于通道十分易用,并且推崇使用通信共享内存,而不是共享内存通信。