zoukankan      html  css  js  c++  java
  • 区块链技术语言(二十七)——Go语言并发编程(上)

    并发编程分为上、下两节。这一节包括了并发编程的概述、goroutine和channel的部分内容。

    一、概述

    1.1

    并行和并发并行(parallel):在多个处理器上同时执行多条指令,如图1所示。

    并发(concurrency):同一时刻只有一条指令在执行,但多个进程指令被快速轮换地执行,使得宏观上具有多个进程同时执行的效果,但在微观上并不是同时执行的。它只是把这段时间进行划分、快速交替地执行,如图2所示。

    1.2 Go语言并发优势

    Go语言原生支持并发。首先,虽然一个并发程序内存管理复杂,但Go语言提供了自动垃圾回收机制,可以自动判断何时需要释放内存,并在CPU相对空闲的时候对不使用的内存进行收集。其次,Go语言提供了goroutine。goroutine即一个函数或方法,它仅需4~5KB的内存,所以创建一个goroutine代价极小。另外,Go语言存在一个内置的数据结构——通道(channel),它能够让不同的goroutine之间同步安全地发送消息。因此,Go语言让并发编程变得更加轻盈和安全。因此,一个运行的程序可以创建成百上千个goroutine,充分利用计算机资源,自动管理内存,实现了高并发。

    二、goroutine

    2.1 goroutine的定义

    关于goroutine,Go语言之父Rob Pike说:“一个goroutine是一个与其它goroutines并发运行在同一地址空间的Go函数或方法。一个运行的程序由一个或更多个goroutine组成。它与线程、协程、进程等不同,它是一个goroutine。”所以我们可以认为goroutine就是一个函数或方法。

    2.2 goroutine的创建和运行

    在函数或者方法的调用语句之前添加关键字go,就可以创建一个goroutine。开发人员无需了解任何执行细节,调度器会自动将其安排到合适的系统线程上执行。当一个程序启动时,其主函数在一个单独的goroutine中运行,这个goroutine叫作main goroutine。新的goroutine用go语句来创建。

    2.2.1 main goroutine

    在Go语言里,主函数运行在main goroutine中,其它goroutines和main goroutine并发运行。如果main goroutine先执行完毕,那么其它的goroutines也会自动退出。

    2.2.2 其它goroutines

    如果要运行所有其它的goroutines,main goroutine必须继续在运行,直到其它goroutines运行完毕。

    2.3 runtime包

    2.3.1 Gosched

    runtime.Gosched() 用于让出当前goroutine的执行权限,调度器安排其他等待的任务运行,并在下次某个时候从该位置恢复执行。

    2.3.2 Goexit

    调用runtime.Goexit(),会立即终止当前goroutine的执行,调度器确保所有已注册defer延迟调用被执行。

    2.3.3 GOMAXPROCS

    调用runtime.GOMAXPROCS() 用来设置可以并行计算的CPU核数的最大值,并且返回设置之前用于并行计算的CPU核数最大值。

    三、channel

    在Go语言里,各个goroutine运行在相同的地址空间,因此访问共享内存必须做好同步。当一个资源需要在两个goroutine之间共享,channel在两个goroutine之间架起一个管道,并提供了确保同步交换数据的机制。可以通过channel共享内置类型、命名类型、结构类型和引用类型的值或指针。channel是基于底层数据结构的引用,当我们复制一个channel或用于函数参数传递时,我们只是拷贝了一个channel引用。和其它的引用类型一样,channel的零值也是nil。

    3.1 channel的创建

    在Go语言中,通过内置函数make可以创建一个channel,需要定义发送到channel的值的类型。其创建格式如下:

    注:a. 当capacity=0时,channel是无缓冲阻塞读写的;
    b. 当capacity>0时,channel有缓冲、非阻塞的,直到写满capacity个元素才阻塞写入。3.2 channel中的数据的发送和接收

    channel通过操作符<-来接收和发送数据,发送和接收数据的语法格式如表1所示。默认情况下,channel接收和发送数据都是阻塞的,除非另一端已经准备好。

    3.3 无缓冲的channel

    3.3.1 概述

    无缓冲的通道(unbuffered channel)是指在接收前没有能力保存任何值的通道。这种类型的通道要求同时准备好发送goroutine和接收goroutine,才能完成发送和接收操作。如果两个goroutine没有同时准备好,通道会导致先执行发送或接收操作的goroutine阻塞等待。这种对通道进行发送和接收的交互行为本身就是同步的,其中任意一个操作都无法离开另一个操作单独存在。图1通过示意图分析了两个goroutine利用无缓冲通道共享一个值:
    a. 第1步,两个goroutine都到达通道两端,但两个都没有开始执行发送数据或者接收数据;
    b. 第2步,左侧的goroutine将它的手伸进通道,这模拟了向通道发送数据的行为。此时,这个goroutine会在通道中被锁住,直到交换完成;
    c. 第3步,右侧的goroutine将它的手放入通道,这模拟了从通道里接收数据。这个goroutine也一样会在通道中被锁住,直到交换完成;
    d. 第4步和第5步,进行数据交换;
    e. 第6步,两个goroutine都将它们的手从通道里拿出来,这模拟了被锁住的goroutine得到释放。两个goroutine现在都可以去做别的事情了。

    3.3.2 无缓冲channel的创建

    无缓冲channel没有指定缓冲区容量,那么在无缓冲的channel中,数据发送和接收同步,其创建格式如下:

    示例如下:

    3.3.3 内置函数close在channel中的应用

    如果发送者知道没有更多的值发送到channel,那么让接收者也能及时知道没有多余的值可接收将是有用的。因为接收者可以停止不必要的接收等待,这可以通过内置的close函数来实现channel的关闭。channel不像文件一样需要经常关闭,只有确实没有任何数据发送到channel,才关闭channel;关闭channel后,无法向channel再发送数据;对于nil channel,无论收发都会被阻塞。

    3.3.4 用range接收channel中的数据

    关键词range结合for循环可用于在一个channel关闭之前,从channel中接收数据。如果要结束此操作,用close函数关闭channel。


    参考资料:


  • 相关阅读:
    转:套接字
    转:Socket原理与编程基础
    转:rabbitmq——用户管理
    转:rabbitMQ 安装与管理
    转:window与linux互相拷贝文件
    转:Xming + PuTTY 在Windows下远程Linux主机使用图形界面的程序
    Rabbitmq集群
    VS2010 win7 64位安装后新建项目生成时错误:LINK : fatal error LNK1123: 转换到 COFF 期间失败: 文件无效或损坏
    java连接sqlserver2008
    Java单体应用
  • 原文地址:https://www.cnblogs.com/efish/p/go-language-concurrency.html
Copyright © 2011-2022 走看看