https://segmentfault.com/a/

Go语言:简介(二)

对Go语言了解前,我们先来补一些基本概念

基本概念

  • 并发程序

一个并发程序可以在一个处理器或者内核上使用多个线程来执行任务,但是只有同一个程序在某个时间点同时运行在多核或者多处理器上才是真正的并行。

并发程序可以是并行的,也可以不是。

  • 多线程缺点

使用多线程的应用难以做到准确,最主要的问题是内存中的数据共享,它们会被多线程以无法预知的方式进行操作,导致一些无法重现或者随机的结果。

使用多线程需要在意同步问题,可能出现死锁,线程上下文切换带来的开销

  • 单线程中大计算量问题

利用多核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