go并发打印数字

60 阅读2分钟

你能用几种方式实现?知道为啥吗?

我们知道go语言最大的特性是:原生支持并发;同时流行一句话:不通过共享内存通讯,通过通讯来共享内存。

这就引出一等公民:channel goroutine

话外音:简单回忆下理论

  1. 进程(process)、线程(thread)、协程(goroutine/coroutine)之间关系如图(网上找的)

​编辑

传统并发编程:多个进程/线程要对临界资源加锁等,通过判断临界资源状态来实现并发。

channl: 通道,多个goroutine可通过channel来通讯。(思考:goroutine通过他实现在通讯中共享内存,可参考GMP模型后面会写)

channel是什么?

简单提下:通过var或make在函数栈上声明8byte的指针,指向堆的hchan的结构体。

有几个核心字段

buf:环形数组(有缓冲的channel)

sendx: 下一个要发送数据的下标

recvx:  下一个要接收数据的下标

sendq: 写队列(发送时,读队列没有goroutine接收,发送的goroutine存在这里)

recvq: 读队列  (接收时, 写队列没有gonroutie发送,接收的goroutine存在这里)

closed: 是否被关闭(关闭可接受零值, 发送panic)

理解了上面:自然也知道为啥有缓channel:buf满-发送阻塞,buf空-接收阻塞

话外音:有无缓冲channel就这点区别。

醒醒,别吹牛X啦,跑题了不就并发打印数字么。。。

话不多说上代码:

type1:

	ch := make(chan int)
	for i := 0; i < 10; i++ {
		go func(i int) {
			ch <- i
		}(i)
	}
	for i := 0; i < 10; i++ {
		print(<-ch)
	}

type2:

func main() {
	ch := make(chan int)
	for i := 0; i < 10; i++ {
		go func(i int) {
			ch <- i
		}(i)
		print(<-ch)
	}
}

这个留个坑,咋避免顺序打印呢(不用type1)

type3:

type worker struct {
	ch   chan int
	done func()
}

func main() {
	quit := make(chan struct{})
	w := worker{
		ch: make(chan int),
		done: func() {
			quit <- struct{}{}
		},
	}
	for i := 0; i < 10; i++ {
		go func() {
			for n := range w.ch {
				print(n)
				w.done()
			}
		}()
	}

	for i := 0; i < 10; i++ {
		w.ch <- i
	}

	for i := 0; i < 10; i++ {
		<-quit
	}
}

type4:

type worker struct {
	ch   chan int
	done func()
}

func main() {
	wg := sync.WaitGroup{}
	w := worker{
		ch: make(chan int),
		done: func() {
			wg.Done()
		},
	}
	for i := 0; i < 10; i++ {
		go func() {
			for n := range w.ch {
				print(n)
				w.done()
			}
		}()
	}
	wg.Add(10)
	for i := 0; i < 10; i++ {
		w.ch <- i
	}
	wg.Wait()
}

话外音:还有很多种写法就,后面在补上。

你瞅瞅理解后不是随便写。。。

专注是最好的学习方法,但不是靠毅力(理性脑有远见却很弱小)。给自己正向反馈,负向更是礼物。共勉。