对Go语言了解前,咱们先来补一些基本概念shell
并发程序多线程
一个并发程序能够在一个处理器或者内核上使用多个线程来执行任务,可是只有同一个程序在某个时间点同时运行在多核或者多处理器上才是真正的并行。并发
并发程序能够是并行的,也能够不是。操作系统
多线程缺点线程
使用多线程的应用难以作到准确,最主要的问题是内存中的数据共享,它们会被多线程以没法预知的方式进行操做,致使一些没法重现或者随机的结果。设计
使用多线程须要在乎同步问题,可能出现死锁,线程上下文切换带来的开销code
单线程中大计算量问题协程
利用多核CPU,将计算分发到各个子进程,将大量的计算分解掉,而后再经过进程间的事件消息来传递结果。接口
goroutines(协程)队列
1.协程与线程关系
在协程和操做系统线程之间并没有一对一的关系:协程是根据一个或多个线程的可用性,映 射(多路复用,执行于)在他们之上的;协程调度器在 Go 运行时很好的完成了这个工做。
2.协程实现
当系统调用(好比等待 I/O)阻塞协程时,其余协程会继续在其余线程上工做。**协程 的设计隐藏了许多线程建立和管理方面的复杂工做。**
3.协程代价
协程是轻量的,比线程更轻。它们痕迹很是不明显(使用少许的内存和资源):使用 4K 的栈内存就能够在堆中建立它们。由于建立很是廉价,必要的时候能够轻松建立并运行大 量的协程(在同一个地址空间中 100,000 个连续的协程)。
通道只能传输一种类型的数据,好比 chan int 或者 chan string,全部的类型均可以用于通道,空接口 interface{} 也能够。甚至能够(有时很是有用)建立通道的通道。
通道其实是类型化消息的队列:使数据得以传输。它是先进先出(FIFO)结构的因此能够保证发送给他们的元素的顺序(有些人知道,通道能够比做 Unix shells 中的双向管道(tw-way pipe))。
默认状况下,通讯是同步且无缓冲的:在有接受者接收数据以前,发送不会结束。能够想象一个无缓冲的通道在没有空间来保存数据的时候:必需要一个接收者准备好接收通道的数据而后发送者能够直接把数据发送给接收者。因此通道的发送/接收操做在对方准备好以前是阻塞的。
例子:
package main import ( "fmt" "time" ) func main() { ch := make(chan string) go sendData(ch) go getData(ch) time.Sleep(1e9) } func sendData(ch chan string) { ch <- "Washington" ch <- "Tripoli" ch <- "London" ch <- "Beijing" ch <- "Tokio" } func getData(ch chan string) { var input string // time.Sleep(1e9) for { input = <-ch fmt.Printf("%s ", input) } }
输出:
Washington Tripoli London Beijing Tokio