一、Goroute

1. 进程和线程

  •   A. 进程是程序在操作系统中的一次执行过程,系统进行资源分配合调度的一个独立单位

  •   B. 线程是进程的一个执行实体,是CPU调度和分派的基本单位,它是比进程更小的能独立运行的基本单位。

  •   C. 一个进程可以创建和撤销多个线程:同一个进程中的多个线程之间可以并发执行。

2. 并发和并行

  •   A. 多线程程序在一个核的cpu上运行,就是并发

  •   B. 多线程程序在多个核的cpu上运行,就是并行

3. 协程和线程

  • 协程:独立的栈空间,共享栈空间,调度由用户自己控制,本质上有点类似于用户级线程,这些用户级线程的调度也是自己实现的

  • 线程:一个线程上可以拍多个协程, 协程是轻量级的线程

package main

import (
"fmt"
"time"
) func test() {
var i int
for {
fmt.Println(i)
time.Sleep(time.Second)
i++
}
} func main() {
go test()
time.Sleep(time.Second * 10)
// for {
// fmt.Println("i' running in main")
// time.Sleep(time.Second)
// }
}

goroutine

4. goroutine调度模型

5. 如何设置golang运行的cpu核数

package main

import (
"fmt"
"sync"
"time"
) type task struct {
n int
} var (
m = make(map[int]uint64)
lock sync.Mutex // 互斥锁
) func calc(t *task) {
var sum uint64
sum = 1
for i := uint64(1); i < uint64(t.n); i++ {
sum *= i
}
fmt.Println(t.n, sum)
lock.Lock()
m[t.n] = sum
lock.Unlock()
} func main() {
for i := 0; i < 16; i++ {
t := &task{n: i}
go calc(t)
}
time.Sleep(time.Second * 10)
lock.Lock()
for k, v := range m {
fmt.Printf("%d! = %v\n", k, v)
}
lock.Unlock()
}

goroute_lock

二、Channel

1.不同的goroutine之间如何进行通讯?

  a. 全局变量和锁同步

  b. Channel

2. channel概念

  a. 类似unix中管道(pipe)

  b. 先进先出

  c. 线程安全,多个goroutine同时访问,不需要de加锁

  d. channel是有类型的,一个整数的channel只能存放整数

3. channel声明

var 变量名 chan 类型
var test chan int
var test chan string
var test chan map[string]string
var test chan stu
var test chan *stu

4. channel初始化

使用make进行初始化,比如:

var test chan int

test = make(chan int, 10)

var test chan string

test = make(chan string, 10)

5. channel基本操作

1. 从channel读取数据
var testChan chan int
testChan = make(chan int, 10)
var a int
a = <- testChan
2. 从channel写入数据
var testChan chan int
testChan = make(chan int, 10)
var a int = 10
testChan <- a
package main

import (
"fmt"
"time"
) func write(ch chan int) {
for i := 0; i < 100; i++ {
ch <- i
fmt.Println("put data: ", i)
}
} func read(ch chan int) {
for {
var b int
b = <-ch
fmt.Println(b)
time.Sleep(time.Second)
}
} func main() {
intChan := make(chan int, 10)
go write(intChan)
go read(intChan) time.Sleep(time.Second * 10)
}

goroutine_chan

6.channel阻塞

7. 带缓冲区的channel

  1. 如下所示,testChan 只能放一个元素

testChan := make(chan int)
var a int
a = <- testChan

  2. 如下所示,testChan是带缓冲区的chan,一次可以放10个元素

testChan = make(chan int, 10)
var a int
testChan <- a
package main

import (
"fmt"
) func send(ch chan<- int, exitChan chan struct{}) {
for i := 0; i < 10; i++ {
ch <- i
}
close(ch)
var a struct{}
exitChan <- a
} func recv(ch <-chan int, exitChan chan struct{}) {
for {
v, ok := <-ch
if !ok {
break
}
fmt.Println(v)
}
var a struct{}
exitChan <- a
} func main() {
var ch chan int
ch = make(chan int, 10)
exitChan := make(chan struct{}, 2) go send(ch, exitChan)
go recv(ch, exitChan)
var total = 0
for _ = range exitChan {
total++
if total == 2 {
break
}
}
}

channel_readline

package main

import "fmt"

type student struct {
name string
} func main() {
var intChan chan int
intChan = make(chan int, 10)
intChan <- 10 var stringChan chan map[string]string
stringChan = make(chan map[string]string, 10)
m := make(map[string]string, 16)
m["stu01"] = ""
m["stu01"] = ""
stringChan <- m var stuChan chan *student
stuChan = make(chan *student, 10)
stu := student{name: "stud01"}
stuChan <- &stu var stuInterChan chan interface{}
stuInterChan = make(chan interface{}, 10)
stu1 := student{name: "stu01"}
stuInterChan <- &stu1 var stu01 interface{}
stu01 = <-stuInterChan fmt.Println(stu01) var stu02 *student
stu02, ok := stu01.(*student)
if !ok {
fmt.Println("can not convert")
return
}
fmt.Println(stu02)
}

channel

8. chan之间的同步 

package main

import (
"fmt"
) func calc(taskChan chan int, resChan chan int, exitChan chan bool) {
for v := range taskChan {
flag := true
for i := 2; i < v; i++ {
if v%i == 0 {
flag = false
break
}
}
if flag {
resChan <- v
}
}
fmt.Println("exit")
exitChan <- true
} func main() {
intChan := make(chan int, 1000)
resultChan := make(chan int, 1000)
exitChan := make(chan bool, 8) go func() {
for i := 0; i < 100000; i++ {
intChan <- i
}
close(intChan)
}()
for i := 0; i < 8; i++ {
go calc(intChan, resultChan, exitChan)
}
// 等待所有的groutine全部退出
go func() {
for i := 0; i < 8; i++ {
<-exitChan
fmt.Println("wait goroute", i, "exited")
}
close(resultChan)
}()
for v := range resultChan {
fmt.Println(v)
}
}

goroutine_sync

package main

import (
"fmt"
) func send(ch chan int, exitChan chan struct{}) {
for i := 0; i < 10; i++ {
ch <- i
}
close(ch)
var a struct{}
exitChan <- a
} func recv(ch chan int, exitChan chan struct{}) {
for {
v, ok := <-ch
if !ok {
break
}
fmt.Println(v)
}
var a struct{}
exitChan <- a
} func main() {
ch := make(chan int, 10)
exitChan := make(chan struct{}, 2)
go send(ch, exitChan)
go recv(ch, exitChan)
var total = 0
for _ = range exitChan {
total++
if total == 2 {
break
}
}
}

goroutine_sync2

9.for range遍历chan

package main

import "fmt"

func main() {
var ch chan int
ch = make(chan int, 1000) for i := 0; i < 1000; i++ {
ch <- i
} close(ch)
for v := range ch {
fmt.Println(v)
}
}

10. chan的关闭

  1. 使用内置函数close进行关闭,chan关闭之后,for range遍历chan中已经放入的元素

  2. 使用内置函数close进行关闭, chan关闭之后,没有使用for range的写法,需要判断chan是否关闭。

示例

package main

import "fmt"

func main() {
var ch chan int
ch = make(chan int, 10) for i := 0; i < 10; i++ {
ch <- i
}
close(ch)
for {
var b int
b, ok := <-ch
if ok == false {
fmt.Println("chan is close")
break
}
fmt.Println(b)
}
}

11. chan的只读和只写

  a. 只读chan的声明

var 变量的名字 <-chan int
var readChan <-chan int

  b.只写chan的声明

var 变量的名字 chan <- int
var writeChan chan <- int
package main

import (
"bufio"
"fmt"
"io"
"os"
) func main() {
file, err := os.Open("test.log")
if err != nil {
fmt.Println(err)
return
}
defer file.Close()
// 带缓存区的文件读写
reader := bufio.NewReader(file)
var line []byte
for {
data, prefix, err := reader.ReadLine()
if err == io.EOF {
break
}
line = append(line, data...)
if !prefix {
fmt.Printf("data: %s\n", string(data))
line = line[:]
}
}
// fmt.Println(line)
}

带缓存区的读写

12.对chan进行select操作

package main

import (
"fmt"
"time"
) func main() {
var ch chan int
ch = make(chan int, 10)
ch2 := make(chan int, 10)
go func() {
var i int
for {
ch <- i
time.Sleep(time.Second)
ch2 <- i * i
time.Sleep(time.Second)
i++
}
}() for {
select {
case v := <-ch:
fmt.Println(v)
case v := <-ch2:
fmt.Println(v)
case <-time.After(time.Second):
fmt.Println("get data timeout")
time.Sleep(time.Second)
}
// var b int
// b = <-ch
// fmt.Println(b)
}
}

13.定时器的使用

package main

import (
"runtime"
"time"
) func main() {
num := runtime.NumCPU()
runtime.GOMAXPROCS(num - 1)
for i := 0; i < 1024; i++ {
go func() {
for {
select {
case <-time.After(time.Microsecond):
// fmt.Println("get data timeout")
}
}
}()
}
time.Sleep(time.Second * 1000)
}

14.一次定时器、超时控制

package main

import (
"fmt"
"runtime"
"time"
) func main() {
num := runtime.NumCPU()
runtime.GOMAXPROCS(num - 1)
for i := 0; i < 16; i++ {
go func() {
for {
t := time.NewTicker(time.Second)
select {
case <-time.After(time.Microsecond):
fmt.Println("timeout")
}
t.Stop()
}
}()
}
time.Sleep(time.Second * 1000)
}

15.goroutine中使用recover

package main

import (
"fmt"
"runtime"
"time"
) func test() {
defer func() {
if err := recover(); err != nil {
fmt.Println("panic:", err)
}
}() var m map[string]int
m["stu"] = 100
} func calc() {
for {
fmt.Println("i'm calc")
time.Sleep(time.Second)
}
} func main() {
num := runtime.NumCPU()
runtime.GOMAXPROCS(num - 1)
go test()
for i := 0; i < 100; i++ {
go calc()
} time.Sleep(time.Second * 1000)
}

三、单元测试

  • 1.文件名必须以_test.go结尾

  • 2. 使用Test开头的函数名作为测试函数

  • 3. 测试案例

package main

func add(a, b int) int {
return a + b
} func sub(a, b int) int {
return a - b
}

calc.go

package main

import (
"encoding/json"
"io/ioutil"
) type student struct {
Name string
Sex string
Age int
} func (p *student) Save() (err error) {
data, err := json.Marshal(p)
if err != nil {
return
}
err = ioutil.WriteFile("stu.dat", data, 0755)
return
} func (p *student) Load() (err error) {
data, err := ioutil.ReadFile("stu.dat")
if err != nil {
return
}
err = json.Unmarshal(data, p)
return
}

student.go

package main

import "testing"

func TestAdd(t *testing.T) {
r := add(2, 4)
if r != 6 {
t.Fatalf("add(2,4) error, expect:%d, actual:%d", 6, r)
}
t.Log("test add succ")
}
func TestSub(t *testing.T) {
r := sub(2, 4)
if r != -2 {
t.Fatalf("sub(2,4) error, expect:%d, actual:%d", -2, r)
}
t.Logf("test sub succ")
}

calc_test.go

package main

import "testing"

func TestSave(t *testing.T) {
stu := &student{
Name: "stu01",
Sex: "man",
Age: 10,
}
err := stu.Save()
if err != nil {
t.Fatalf("save student failed: err%v", err)
}
} func TestLoad(t *testing.T) {
stu := &student{
Name: "stu01",
Sex: "man",
Age: 10,
} err := stu.Save()
if err != nil {
t.Fatalf("save student failed: err%v", err)
}
stu2 := &student{}
err = stu2.Load()
if err != nil {
t.Fatalf("load student failed,err: %v", err)
} if stu.Name != stu2.Name {
t.Fatalf("load student failed, Name not equal")
} if stu.Age != stu2.Age {
t.Fatalf("load student failed, Age not equal")
} if stu.Sex != stu2.Sex {
t.Fatalf("load student failed, Sex not equal")
}
}

student_test.go

package main

main.go

Go语言系列(八)- Goroute和Channel的更多相关文章

  1. C语言高速入门系列(八)

    C语言高速入门系列(八) C语言位运算与文件 本章引言: 在不知不觉中我们的C高速入门系列已经慢慢地接近尾声了,而在这一节中,我们会对 C语言中的位运算和文件进行解析,相信这两章对于一些人来说是陌生的 ...

  2. Netty 源码解析(八): 回到 Channel 的 register 操作

    原创申明:本文由公众号[猿灯塔]原创,转载请说明出处标注 今天是猿灯塔“365篇原创计划”第八篇. 接下来的时间灯塔君持续更新Netty系列一共九篇 Netty 源码解析(一): 开始 Netty 源 ...

  3. Keil MDK STM32系列(八) STM32F4基于HAL的PWM和定时器输出音频

    Keil MDK STM32系列 Keil MDK STM32系列(一) 基于标准外设库SPL的STM32F103开发 Keil MDK STM32系列(二) 基于标准外设库SPL的STM32F401 ...

  4. 微软云平台windows azure入门系列八课程

    微软云平台windows azure入门系列八课程: Windows Azure入门教学系列 (一): 创建第一个WebRole程序与部署 Windows Azure入门教学系列 (二): 创建第一个 ...

  5. Java语言基础(八)

    Java语言基础(八) 一.数学运算  + - * /  % (1)凡是byte  short  char类型都按int类型的计算   看看上面的代码,为什么出错! 我已经将100转成byte类型,( ...

  6. SQL Server 2008空间数据应用系列八:基于Bing Maps(Silverlight)的空间数据存储

    原文:SQL Server 2008空间数据应用系列八:基于Bing Maps(Silverlight)的空间数据存储 友情提示,您阅读本篇博文的先决条件如下: 1.本文示例基于Microsoft S ...

  7. Swift语言指南(八)--语言基础之元组

    原文:Swift语言指南(八)--语言基础之元组 元组 元组(Tuples)将多个值组合为一个复合值.元组内的值可以是任何类型,各个元素不需要为相同类型(各个元素之间类型独立,互不干扰--Joe.Hu ...

  8. java多线程系列(八)---CountDownLatch和CyclicBarrie

    CountDownLatch 前言:如有不正确的地方,还望指正. 目录 认识cpu.核心与线程 java多线程系列(一)之java多线程技能 java多线程系列(二)之对象变量的并发访问 java多线 ...

  9. C语言第八讲,指针*

    C语言第八讲,指针* 一丶简单理解指针 说到指针,很多人都说是C语言的重点. 也说是C语言的难点. 其实指针并不是难.而是很多人搞不清地址 和 值.以及指针类型. 为什么这样说. 假设有两个变量,如下 ...

  10. R语言系列:生成数据

    R语言系列:生成数据 (2014-05-04 17:41:57) 转载▼ 标签: r语言 教育 分类: 生物信息 生成规则数据1.使用“:“,如x=1:10,注意该方法既可以递增也可以递减,如y=10 ...

随机推荐

  1. SQL SERVER 索引碎片

    一次发现同样的SQL在线上库和复制库执行时间差好多,重新创建相关表索引,性能提升明显,怀疑索引有碎片

  2. 做移动端电子签名发现canvas的 一些坑

    做移动端收集电子签名项目的时候发现了一些坑: 1. 移动端的手指按下.移动.抬起事件跟PC端的鼠标按下.移动.弹起事件是不一样的 2. canvas它的属性宽高和样式宽高是不一样的,通过CSS来设置c ...

  3. tomcat报异常Invalid character found in method name. HTTP method names must be tokens

    最近监控了一下测试环境的日志,突然出现如下一个异常 由Error parsing HTTP request header可以看出是由于解析请求头出错导致的,但是它属于DEBUG级别的异常,虽然不影响系 ...

  4. 理论铺垫:阻塞IO、非阻塞IO、IO多路复用/事件驱动IO(单线程高并发原理)、异步IO

    完全来自:http://www.cnblogs.com/alex3714/articles/5876749.html 同步IO和异步IO,阻塞IO和非阻塞IO分别是什么,到底有什么区别?不同的人在不同 ...

  5. Python简单多进程demo

    ''' 多线程使用场景: 怎样用Python的多线程提高效率? io操作不占用CPU 计算操作占用CPU Python多线程不适合CPU操作密集型的任务,适合io操作密集型的任务 如果有CPU操作密集 ...

  6. 跨域 - 自定义 jsonp实现跨域

    问题:在现代浏览器中默认是不允许跨域. 办法:通过jsonp实现跨域   在js中,我们直接用XMLHttpRequest请求不同域上的数据时,是不可以的.但是,在页面上引入不同域上的js脚本文件却是 ...

  7. [LeetCode] 6. Z 字形变换

    题目链接:(https://leetcode-cn.com/problems/zigzag-conversion/) 题目描述: 将一个给定字符串根据给定的行数,以从上往下.从左到右进行 Z 字形排列 ...

  8. python之shutil

    ''' shutil 用来处理 文件 文件夹 压缩包 的模块 ''' import shutil # 拷贝文件内容 shutil.copyfileobj(open('old.xml', 'r'), o ...

  9. typeScript面对对象篇一

    面向对象是typescript的核心部分,这里先介绍下面向对象的七大原则: 单一原则:一个类子负责一个职责. 里氏替换原则:子类可以在任何地方替换它的父类. 依赖倒置原则:代码要依赖于抽象的类,而不要 ...

  10. 数据接口测试工具 Postman 介绍

    此文介绍好用的数据接口测试工具 Postman,能帮助您方便.快速.统一地管理项目中使用以及测试的数据接口. 1. Postman 简介 Postman 一款非常流行的 API 调试工具.其实,开发人 ...