精髓

将资源读进内存-->共享内存,一个个进程/线程进行处理,这是常见模式。go channel 是一种直接在进程/线程之间传递资源的方式,即以通信来共享内存。这便是go的精髓。

扩展-一些名词了解

Linux、IPC(进程间通信)、进程(六个状态)、线程、同步、异步、信号、管道、socket、消息队列、字节流、结构化消息、通信、信号量、共享内存、内核空间、用户空间、PID、PPID、fork、COW

将进程细化为多个状态后,系统CPU就可以更加灵活地调度,进程下还有更细的线程,有N多状态,

GO调度器实现一套机制,统一调度与分配这些CPU、进程、线程等资源,分为M(内核)、P(go上下文)、G(goroutine)三层

以上概念不学linux原理的话,听个名词就好,GO中重点学习两个点

1. 第三层G就是我们经常使用的goroutine协程,掌握goroutine的使用

2. GO支持的IPC方法有 信号、管道、socket,掌握这三种的实现方式

1. 掌握goroutine的使用

---------------------------------------------------------------------------------------------------------

定义

chan T      双向

chan<-T   只发送

<- chan T 只接收

通道类型,也是引用类型,零值为nil

特性

同一时刻,仅有一个goroutine可以向该通道发送元素值,同时也仅有一个goroutine可以从该通道接收元素值,即通道是串行的。

通道中的元素值,严格按发送到该通道的先后顺序排列,最先发送到的元素值,一定最先被接收。等效于先进先出的消息队列。

通道中的元素值,具有原子性,不可被分割;每个元素值只能被一个goroutine接收,被接收后,立刻从通道中清除。

goroutine的执行与主程序是并行的,主程序结束时,还没有执行完毕的goroutine会被强制中止。

通道的传值是复制,不是引用。

通道初始化

通道未初始化时其值为nil,可以从nil中尝试接收元素,但会被永远阻塞

make(chan int)

初始化一个可以接收、发送int值类型的通道,无缓冲

make(chan int, 10)

初始化一个可以接收、发送int值类型的通道,可缓冲10个int值。第11个int值向通道中发送时会被阻塞。

被缓冲的元素值,会严格按发送的顺序接收。

从通道中接收元素

c := make(chan int, 10)

n := <- c

如果通道 c 被关闭,那么n的值为该元素类型的零值,本例int类型的零值为0;如果是在接收的过程中被关闭了,n的值同样为0。

package main

import "fmt"

func main() {
c:= make(chan int,10)
close(c)
n:=<-c
fmt.Println(n)
}

n,ok := <- c

这种写法与上面的唯一区别在于,当通道关闭时,ok的值为false

package main

import "fmt"

func main() {
c:= make(chan int,10)
close(c)
n,ok:=<-c
fmt.Println(n,ok) // 0 false
}

 让后台协程有序执行

本例很好地诠释了前面的概念描述。tools包是个人自定义包,尝试运行时,可自行修改一下代码,个人为了方便就不再更改本地环境代码了。

package main

import (
"sync"
"time"
"tools"
) func main() {
startTask()
} func startTask() { cmdList := make([]string,6)
cmdList[0] = "mkdir -p /opt/test/dir1"
cmdList[1] = "mkdir /opt/test/dir1/dir2"
cmdList[2] = "mkdir /opt/test/dir1/dir2/dir3"
cmdList[3] = "mkdir /opt/test/dir1/dir2/dir3/dir4"
cmdList[4] = "mkdir /opt/test/dir1/dir2/dir3/dir4/dir5"
cmdList[5] = "mkdir /opt/test/dir1/dir2/dir3/dir4/dir5/dir6" var cmdLength = len(cmdList)
var cmdChan = make(chan string,cmdLength) var onOff = make(chan int,cmdLength) var wg sync.WaitGroup
wg.Add(cmdLength)
for i,cmd := range cmdList {
cmdChan <- cmd
go task(&cmdChan,&onOff,&wg,i,cmdLength)
}
//启动第一个任务,第一个任务结束时会启动第二个任务,依次类推
onOff <- 0
wg.Wait()
} func task(cmdChan *chan string,onOff *chan int,wg *sync.WaitGroup, seq,maxLength int) { for {
if i,ok := <- *onOff; ok {
if i == seq {
//跳出循环等待,开始当前顺序命令执行
break
}else {
//将取出的命令执行序号放回通道,然后暂停一段时间该后台协程
*onOff <- i
//让不该执行的后台协程等待,就会让该执行的后台线程更容易获取执行机会,因为它不用等
time.Sleep(10*time.Microsecond) }
}
} //从缓冲中取出的元素顺序,严格遵从放入时的顺序
//所以取出的顺序一定会按命令列表的下标从0排列到列表结束
if cmd,ok := <- *cmdChan; ok{
tools.ExecShell(cmd)
}
wg.Done() seq++
if seq < maxLength{
*onOff <- seq
} }

linux mkdir有个特性,其父目录若不存在,则无法创建子目录;若命令不按列表顺序执行,那么最后的目录肯定不会创建成功,

若成功创建所有目录,则表明命令是按顺序执行的。

若去掉onOff顺序控制,本例就是一个后台并发执行的例子。

 关闭通道

通常在发送端关闭通道

不可重复关闭通道,关闭一个已经关闭的或未初始化的通道会引发异常

通道关闭后,其中未接收的数据仍可被接收

接收端应先判断通道是否关闭再从中取值,否则若通道关闭可能取出的值是通道类型的零值

package main

import "fmt"

func main() {
dataChan := make(chan int,3)
startChan := make(chan string,1)
overChan := make(chan string,2) go func() {
<- startChan
fmt.Println("start receive data ")
for{
if elem,ok:= <- dataChan; ok{
fmt.Printf("%v\n",elem)
}else {
break
}
}
fmt.Println("reciver over")
overChan <- "rec over"
}() go func() {
for i:=0;i<3;i++ {
dataChan <- i
fmt.Sprintf("send data:%v\n",i)
} fmt.Println("send data over")
//在接收之前关闭通道
close(dataChan)
fmt.Println("dataChan closed") //开始接收
startChan <- "begin" overChan <- "send data over"
}() <- overChan
<- overChan
fmt.Println("main over") }

 长度与容量

长度是通道中元素的个数,非固定值

容量是通道中可能缓存的元素个数

package main

import "fmt"

func main() {

    c1 := make(chan int,5)
fmt.Printf("c1 长度:%v, 容量:%v\n",len(c1),cap(c1)) c2 := make(chan int)
fmt.Printf("c2 长度:%v, 容量:%v\n",len(c2),cap(c2))
}
c1 长度:0, 容量:5
c2 长度:0, 容量:0

 单向通道

chan T      双向    用于channel定义

chan<-T   只发送  用于接口、函数参数定义

<- chan T 只接收  用于接口、函数参数定义

双向通道可以转换为发送/接收通道,反之不可以。

 for 与 channel

可以从未初始化的通道(nil)中取值,但会被阻塞

当通道关闭时,会将通道中的元素全部取出后,语句结束

必须是一个双向通道或接收通道,不是只是发送通道。

    var c3 chan int
for elem := range c3 {
fmt.Println(elem)
}

 Linux进程

linux进程通过调用系统函数fork创建,首个系统进程为/usr/bin/sbin,其他进程都是该进程的子进程,呈现树状结构。

进程创建方式:复制父进程的数据段、堆、栈等数据,共享父进程的代码段,复制后子进程、父进程相互间是独立的。系统内核通过写时复制(copy on write,COW)来提高创建进程的效率。

Linux进程详细的结构如下,大致分为四部分 代码区(Text segment)-只读静态区,Data段,Heap段,Stack段。

 进程状态图

注意这里的僵尸状态,是不是僵尸状态是子进程反馈给父进程的,如果子进程自己发生意外,无法给父进程反馈但还一直存在着,那么子进程的状态可能会成为僵尸状态

SIGCHILD只是在子进程退出的时候发送给父进程的一个信号值,这是一种异步通知父进程的方式.父进程可以捕获,忽略这个信号,默认动作是忽略此信号.
常用的使用方式是,当SIGCHILD信号发生时候,主进程在SIGCHILD的信号处理函数中调用waitpid or wait来回收子进程的结束状态。但需要明白的是:waitpid or wait不是依靠SIGCHLD信号是否到达来判断子进程是否结束,(可能是通过轮巡检测子进程状态来判断的,需要看具体代码实现才能确定),即wait/waitpid并不依赖于SIGCHILD信号.常常在SIGCHILD的信号处理函数中调用 wait/waitpid回收子进程状态是为了避免wait/waitpid不必要的轮巡,是属于一种节约资源的方式,但这并不是必须的。

未完.....

go channel 概述的更多相关文章

  1. Channel概述

    前言 前两篇文章介绍了NIO核心部分部分之一的缓冲区的相关内容,接下来我们继续学习NIO中另一个重要的核心部分--Channel(通道). 在学习这篇文章之前,先做下简单的说明,本文是一篇关于通道的概 ...

  2. go channel 概述 - 管道

    概述 unix/linux OS 的一个进程的输出可以是另一个进程的输入,这些进程使用stdin与stdout设备作为通道,在进程之间传递数据. 同样的,GO中有io.Reader与io.Writer ...

  3. Channel延续篇

    上篇文章中介绍了NIO中的Channel,从Channel是什么.特性.分类几个方面做了下简单的介绍.但是后面Channel的分类,个人感觉不够全面,容易误导读者,特此以这篇文章加以补充. Chann ...

  4. 详解 通道 (Channel 接口)

    在本篇博文中,本人主要讲解NIO 的两个核心点 -- 缓冲区(Buffer) 和 通道 (Channel)之一的 缓冲区(Buffer), 有关NIO流的其他知识点请观看本人博文<详解 NIO流 ...

  5. NIO(二):Channel通道

    一.Channel概述 channel(通道):进行IO的连接通道,为NIO的几个核心(Buffer,selector,channel)之一,相比于IO的stream具有较高的性能. IO 单向传输 ...

  6. NIO类库

    NIO概述 从JDK1.4开始,引入了新的I/O类库,它们位于java.nio包中,其目的在于提高I/O的操作效率.nio是new io的缩写. 参考文章:NIO BIO AIO区别 java.nio ...

  7. SocketChannel简述

    前言 在前面的Channel概述的分类中提到过SocketChannel主要是用来基于TCP通信的通道.这篇文章详细介绍下SocketChannel SocketChannel是什么 SocketCh ...

  8. Java:NIO 学习笔记-3

    Java:NIO 学习笔记-3 根据 黑马程序员 的课程 JAVA通信架构I/O模式,做了相应的笔记 3. JAVA NIO 深入剖析 在讲解利用 NIO 实现通信架构之前,我们需要先来了解一下 NI ...

  9. GO 总章

    GO 学习资源 go 代理 GO 语言结构 GO 数字运算 GO 时间处理 GO 定时器 GO 异常处理 go recover让崩溃的程序继续执行 GO Exit Fatal panic GO 通过进 ...

随机推荐

  1. HTML基本使用

    HTML初识 (Hyper Text Markup Language): 超文本标记语言 「HTML骨架格式」 <!-- 页面中最大的标签 根标签 --> <html> < ...

  2. 多线程 | 03 | CAS机制

    Compare and swap(CAS) 当前的处理器基本都支持CAS,只不过每个厂家所实现的算法并不一样罢了,每一个CAS操作过程都包含三个参数:一个内存地址V,一个期望的值A和一个新值B,操作的 ...

  3. #web开发# 知道cookie hostonly属性的请举手。

    Cookie常见姿势.疑难梳理 目前w3c定义浏览器存放每个cookie需要包含以下字段: cookie属性 基本描述 举例 备注 name=value cookie键值对 id=a3fWa expi ...

  4. C++ substr 的两个用法

    substr是C++语言函数,主要功能是复制子字符串,要求从指定位置开始,并具有指定的长度.   basic_string substr(size_type _Off = 0,size_type _C ...

  5. Python 操作 Redis 发布订阅

    Python 操作 Redis 发布订阅 介绍 Redis可以通过多个客户机订阅相同的频道,一个服务机在相应频道进行发布,从而实现在客户机收听服务机发布相应信息,可以利用这个机制实现多个客户机之间的信 ...

  6. b站个人直播年报【大爽歌作】 介绍与演示

    大家好,我是大爽,一个b站UP主兼主播. 最近做了一个b站直播个人年报,该年报为代码文件生成. 且代码已打包到一个可视化工具中(exe)只需两步就可以获得自己的专属年报. 代码已上传到我的github ...

  7. [loj2842]野猪

    首先,并不一定走"除了上一次来的边"以外的最短路,但考虑"除了上一次来的边"以外的最短路和次短路(这里的次短路指最后一条边与最短路不同的"最短路&qu ...

  8. 下载安装wps后去除监控

    下载wps之后发现wps一直对我的电脑进行监控,占用着我的cpu和内存,我要把它清理出去.... 控制面板→管理工具→任务计划程序→任务计划程序库,有两个wps的任务计划,可以根据属性看到文件地址 C ...

  9. .NET E F(Entity Framework)框架 DataBase First 和 Code First 简单用法。

    EF是微软.NET平台官方的ORM(objet-relation mapping),就是一种对象-关系 映射,是将关系数据库种的业务数据用对象的形式表现出来,并通过面向对象的方式讲这些对象组织起来,实 ...

  10. [NOI2020] 美食家

    很好,自己会做NOI签到题了,去年只要会这题,再多打点暴力,\(Ag\)到手,希望今年\(NOI\)同步赛过\(Ag\)线吧,得有点拿得出手的成绩证明啊. 考虑\(T\)非常大,\(n\)又很小. 想 ...