一、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. 从0开始的Python学习007函数&函数柯里化

    简介 函数是可以重用的程序段.首先这段代码有一个名字,然后你可以在你的程序的任何地方使用这个名称来调用这个程序段.这个就是函数调用,在之前的学习中我们已经使用了很多的内置函数像type().range ...

  2. 基于TCP 协议的RPC

    前言: 环境: windown 10 Eclipse JDK 1.8 RPC的概念: RPC 是远程过程调用,是分布式网站的基础. 实验 SayHelloService.java 接口类,用于规范 S ...

  3. Centos7上安装docker (转)

    Centos7上安装docker Docker从1.13版本之后采用时间线的方式作为版本号,分为社区版CE和企业版EE. 社区版是免费提供给个人开发者和小型团体使用的,企业版会提供额外的收费服务,比如 ...

  4. 【导航】Python相关

    [博客导航] Python相关导航 [索引]Python常用资源(从新手到大牛) [任务]Python语言程序设计.MOOC学习 [笔记]Python集成开发环境——PyCharm 2018.3下载. ...

  5. RESTful API规范

    1. 域名 应该尽量将API部署在专用的域名下. https://api.example.com 如果确定API简单,不会有进一步的括在,可以考虑放在主域名之下. https://example.or ...

  6. Jenkins之Job建立-运行本地脚本

    新建一个自由风格的项目,运行本地脚本 1.点击菜单栏中的“新任务” 2.进入该页面后输入一个项目名称,然后选择“构建一个自由风格的软件项目”,滑动到最底端,点击ok(在左下角) 3.进入下图页面后 “ ...

  7. java 下载word freemaker

    网上有很多优质的博文了,这里这篇博客就是记录一下字自己,写demo的历程,坑和收获 在java程序中下载word 有6中方式,此处省略(嘻嘻),不过大家公认的是 freemaker 和 PageOff ...

  8. 【转】Android开发:Service和Thread的关系

    不少Android初学者都可能会有这样的疑惑,Service和Thread到底有什么关系呢?什么时候应该用Service,什么时候又应该用Thread?答案可能会有点让你吃惊,因为Service和Th ...

  9. ORACLE 常见等待事件

    一. 等待事件的相关知识 1.1 等待事件主要可以分为两类,即空闲(IDLE)等待事件和非空闲(NON-IDLE)等待事件.1). 空闲等待事件指ORACLE正等待某种工作,在诊断和优化数据库的时候, ...

  10. 问题记录2019-03-06(todo)

    RuntimeError: maximum recursion depth exceeded while calling a Python object