Go并发实践之 goroutine

Posted BBinChina

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Go并发实践之 goroutine相关的知识,希望对你有一定的参考价值。

老生常谈之: 进程、线程

在并发编程方面, 我们绕不开操作系统、进程与线程这些概念,线程是操作系统调度执行时的最基本单元。Linux系统对于线程实现非常特殊,他并不区分线程和进程,线程只是一种特殊的进程罢了,也即是说不同操作系统也有不同的实现,但在进程、线程的区分上有着以下标准:

  • 进程:

    1、拥有一段可执行程序代码,也即是代码段。代码段可以被多个进程共用,独立加载在每个进程内存空间。
    2、拥有一段进程专用的系统堆栈空间,也即进程内存空间,包括 代码段(code segment)、数据段(data segment)、静态内存(BBS segment)、堆(heap)、栈(stack)。

  • 线程:

    1、线程是进程中的一部分、一个进程可以由多个线程,但线程只能存在于一个进程中。

  • 联系:

    1、多个线程可以属于同一个进程并共享内存空间。因为多线程不需要创建新的虚拟内存空间,所以它们也不需要内存管理单元处理上下文的切换,线程之间的通信也正是基于共享的内存进行的,与重量级的进程相比,线程显得比较轻量。
    2、虽然线程比较轻量,但是在调度时也有比较大的额外开销。每个线程会都占用 1M 以上的内存空间,在切换线程时不止会消耗较多的内存,恢复寄存器中的内容还需要向操作系统申请或者销毁资源,每一次线程上下文的切换都需要消耗 ~1us 左右的时间。

多线程模型

并发模型中经常使用到的便是多线程模型,前文讲到,线程是操作系统调度的最基本单元,通过在同一时间创建多个线程,每个线程执行不同的任务,可以提高我们程序的任务执行能力。
但同时,多线程模型也引入了一个问题,多线程任务共享进程资源便利的同时,多线程对共享的资源存在竞争,便用到了锁机制,不展开科普。

Golang的多线程机制 Goroutine

Golang关于并发编程,提出了Goroutine的实现机制,Goroutine是一种轻量级线程,Goroutine的调度由Golang的Runtime运行时进行管理,关于Runtime机制需要再做分析。

Goroutine的语法格式:

go 函数名( 参数列表 )
例如:

go f(x, y, z)

在一个程序中使用go关键字开启的Goroutine都共享同一内存空间。共享内存空间可以实现线程间的通信,同时也带来了资源竞争问题。
在Golang中,天然提供了通道方式的线程间通信机制,即Channel。

Channel可用于两个 goroutine 之间通过传递一个指定类型的值来同步运行和通讯。操作符 <- 用于指定通道的方向,发送或接收。如果未指定方向,则为双向通道。

//先声明通道,及其通信内容
ch := make(chan int)

ch <- v    // 把 v 发送到通道 ch
v := <-ch  // 从 ch 接收数据
           // 并把值赋给 v

PS:
默认情况下,通道是不带缓冲区的。发送端发送数据,同时必须有接收端相应的接收数据。

如果设置缓冲区的话,相当于实现了队列,就是说发送端发送的数据可以放在缓冲区里面,可以等待接收端去获取数据,而不是立刻需要接收端去获取数据。不过由于缓冲区的大小是有限的,所以还是必须有接收端来接收数据的,否则缓冲区一满,数据发送端就无法再发送数据了。

PS:
带缓存区与不带缓存区的区别在于消息数量,不带缓冲区相当于可容纳数量为1,但消费端未消费时,发送端始终阻塞等待缓冲区为空才能发送下一条数据。

Go 通过 range 关键字来实现遍历读取到的数据,类似于与数组或切片。格式如下:

v, ok := <-ch

同时,可以通过调用Close()来关闭Channel

ch.close()

Rust的并发编程

多线程Web服务器

demo:

use std::thread;
use std::sync::mpsc;

fn main() {
    let (tx, rx) = mpsc::channel();

    thread::spawn(move || {
        let val = String::from("hi");
        tx.send(val).unwrap();
    });

    let received = rx.recv().unwrap();
    println!("Got: {}", received);
}

主要使用的Rust库sync 实现线程间通信。

管道的通信方式都是接收端未消费时,发送端进行了堵塞

以上是关于Go并发实践之 goroutine的主要内容,如果未能解决你的问题,请参考以下文章

Go 语言基础 之 并发和网络

GO的并发之道-Goroutine调度原理&Channel详解

Go语言基础之并发

Go语言系列之并发编程

golang 碎片整理之 并发

Go语言基础之并发