区块链开发 Go语言:并发编程

Posted 二向箔区块链开发

tags:

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

姜富耀 | 孔壹社区成员,致力于区块链开发技术共享

博客:http://jiangfuyao.com

孔壹学院 -- 全国首家区块链开发系统性培训机构。   http://kongyixueyuan.com


串行 并发 的概念

进程:一个正在运行的程序一般就是一个进程,一个进程可以包含多个线程。
线程:一堆有序的CPU命令的集合体
注意:一个CPU在同一时刻只能执行一个CPU命令。
假设我现在只有一个CPU,那么进行多线程编程,是通过 上下文切换,时间片的轮转分配。

1.并发编程:多个线程,会有时间片的分配问题。多个线程之间会不断的来回切换。
2.串行编程:根据添加线程的顺序,按照顺序,一一去执行。

CPU有如下两种:
1.物理CPU
2.逻辑CPU(虚拟CPU)
一个 物理CPU可以虚拟出多个逻辑CPU
8核 同一时刻可以同时最多执行8个CPU命令。

多线程编程优点: 分线程可以处理耗时操作,不会出现主线程阻塞。
多线程编程缺点:资源竞争,内存消耗,出现死锁。

出现 进程阻塞 案例

//主线程 : 按照一定有序的CPU命令的顺序来依次执行。

func main()  {
 fmt.Println("foo() start")
 foo()
 fmt.Println("bar() start")
 bar()
}

func foo()  {
 for i := 0;i < 1000000000;i++ {//当计算时间很长时间,就会出现线程阻塞
   fmt.Println("i:",i)
 }
}

func bar()  {
 for j := 0;j < 200;j++ {
   fmt.Println("j:",j)
 }
}

runtime: 有两种形式,一种是一条直线,另一种是一个圈。
下面的Demo案例中,仍然是一条直线。
当程序执行到主函数中最后一个 } 时,分线程还没执行,整个程序结束

func main()  {
 fmt.Println("foo() start")
 go foo() //产生一个分线程,(把foo()的执行,放到分线程中。)
 fmt.Println("foo() end")
 fmt.Println("bar() start")
 go bar() //把bar()的执行,放到分线程中,
 fmt.Println("bar() end")
}
func foo()  {
 for i := 0;i < 100;i++ {
   fmt.Println("i",i)
 }
}
func bar()  {
 for j := 0;j < 200;j++ {
   fmt.Println("j",j)
 }
}

下面这个Demo里面,runtime是一个圆环,主线程一直不停,一直等待 分线程执行完,才结束。

package main

import (
 "fmt"
 "sync"
)

// wg是一个队列,主要用于管理线程。
var wg sync.WaitGroup

func main()  {
 wg.Add(2) //添加两个线程。(添加线程的个数)
 go foo() //把foo()所有任务放到分线程
 go bar() //把bar()所有任务放到分线程
 wg.Wait()// 主线程需要等待分线程去执行,只有队列中counter 计数器的值变为0时,主线程才会结束。runtime为一个圆圈。
}

func foo()  {
 for i := 0; i < 10; i++ {
   fmt.Println("i",i)
 }
 wg.Done() //当分线程的任务处理完成,counter计数器 减 1
}
func bar()  {
 for j := 0;j < 20;j++ {
   fmt.Println("j",j)
 }
 wg.Done() //当分线程的任务处理完成,counter计数器 减 1
}

进程休眠

package main

import (
 "fmt"
 "sync"
 "time"
)
var wg sync.WaitGroup

func main()  {
 wg.Add(2) //添加两个分线程。(添加分线程的个数)
 go foo() //把foo()所有任务放到分线程
 go bar() //把bar()所有任务放到分线程
 wg.Wait()// 主线程需要等待分线程去执行,只有队列中counter 计数器的值变为0时,主线程才会结束。
}

func foo()  {
 for i := 0; i < 10; i++ {
   fmt.Println("i",i)
   time.Sleep(3 * time.Second) //休眠3秒
 }
 wg.Done() //当分线程的任务处理完成,counter计数器 减 1
}
func bar()  {
 for j := 0;j < 20;j++ {
   fmt.Println("j",j)
   time.Sleep(20 * time.Second) //休眠20秒
 }
 wg.Done() //当分线程的任务处理完成,counter计数器 减 1
}

读取 CPU个数,以及设置 参与执行的CPU的个数

package main

import (
   "fmt"
   "runtime"
   "sync"
   "time"
)

var wg sync.WaitGroup

// runtime.NumCPU() 逻辑CPU个数
// runtime.GOMAXPROCS设置机器能够参与执行的CPU的个数
// init()方法会在main函数之前执行
func init() {
   fmt.Println("init()")
   fmt.Println(runtime.NumCPU())

   runtime.GOMAXPROCS(runtime.NumCPU())
}

func main() {
   fmt.Println("main() start()")
   wg.Add(2)
   go foo()
   go bar()
   wg.Wait()
}

func foo() {
   for i := 0; i < 45; i++ {
       fmt.Println("Foo:", i)
       time.Sleep(3 * time.Millisecond)
   }
   wg.Done()
}

func bar() {
   for i := 0; i < 45; i++ {
       fmt.Println("Bar:", i)
       time.Sleep(20 * time.Millisecond)
   }
   wg.Done()
}

终端 运行 $ go run -race main.go检查 是否有资源竞争。

资源竞争案例

package main

import (
 "fmt"
 "time"
)

func main()  {
 a := 1
 go func ()  { //匿名函数,分线程
   a = 2
   fmt.Println("a is func ",a)
 }()
 a =3  //主线程改为3,休眠,分线程改为2,所以结果都为2。
 time.Sleep(2 * time.Second)
 fmt.Println("a is main ", a)
}

生成随机数

package main

import (
 "fmt"
 "math/rand"
 "time"
)

//随机生成一个10以下的随机数
func main()  {
 rand.Seed(time.Now().UnixNano())//时间种子,不设置的话,每次生成的随机数相同。
 randNum := rand.Intn(20)
 fmt.Println(randNum)
}

互斥 和 上锁

var mutex sync.Mutex //互斥

mutex.Lock() //上锁
//上锁后被锁定的内容,不会被 两个或多个线程修改。
mutex.Unlock() //解锁

原子操作

package main
import (
 "fmt"
 "math/rand"
 "sync/atomic" //原子操作
)

//原子操作:下面代码是让 counter +1,但是无法使第二行代码不被人改变。
atomic.AddInt64(&counter, 1)
fmt.Println(.....)

json 格式 编码、解码,流式编解码

把 对象属性 进行 json 格式字符串 (编码)

//利用普通编码将结构体对象的属性数据导出为json格式
import (
 "fmt"
 "encoding/json"
)
type Person struct {
 Name string
 Age string
 Id string
}
func main()  {
 p1 := Person{"jiangfuyao","20","100"}
 p2 := Person{"jiangfuyao","20","101"}
 p3 := Person{"jiangfuyao","20","102"}
 p4 := Person{"jiangfuyao","20","103"}
 var arrPerson = [4]Person{p1,p2,p3,p4}
 var arrJson =[4]string{}
 for key,value := range arrPerson {

   bs, err := json.Marshal(value)
   if err == nil {
     //转换成功
     // fmt.Println(string(bs))
     arrJson[key] = string(bs)

   }
 }
 fmt.Println(arrJson)
}

把json格式字符串,转换成 对象属性储存 (解码)

package main
import (
 "fmt"
 "encoding/json"
)
type Person struct {
 Name string  `json:"name"`
 Age string   `json:"age"`
 Id string    `json:"id"`
}
func main()  {
 personArr := [3]Person{}
 bs := []byte(`[{"name":"jiangfuyao","age":"20","id":"100"},{"name":"jiangfuyao","age":"20","id":"101"},{"name":"jiangfuyao","age":"20","id":"102"},{"name":"jiangfuyao","age":"20","id":"103"}]`)
 json.Unmarshal(bs, &personArr)
 for _,value := range personArr {
   fmt.Println(value)
 }
}

流式编码,将结构体对象的属性数据导出为json格式

package main
import (
 "encoding/json"
 "os"
)
type Person struct {
 Name string
 Age string
 Id string
}
func main()  {
 p1 := Person{"jiangfuyao","20","100"}
 p2 := Person{"jiangfuyao","20","101"}
 p3 := Person{"jiangfuyao","20","102"}
 p4 := Person{"jiangfuyao","20","103"}
 var arrPerson = [4]Person{p1,p2,p3,p4}
json.NewEncoder(os.Stdout).Encode(arrPerson)
}

流式 解码

package main
import (
 "encoding/json"
   "fmt"
   "strings"
)
type Person struct {
 Name string  `json:"name"`
 Age string   `json:"age"`
 Id string    `json:"id"`
}
func main()  {
 var personArr = [3]Person{}
 rdr := strings.NewReader(`[{"name":"jiangfuyao","age":"20","id":"100"},{"name":"jiangfuyao","age":"20","id":"101"},{"name":"jiangfuyao","age":"20","id":"102"},{"name":"jiangfuyao","age":"20","id":"103"}]`)
 json.NewDecoder(rdr).Decode(&personArr)
 for _,value := range personArr {
   fmt.Println(value)
 }
}

日后随着 学习打怪的不断深入,会解锁其他的高级教程。  

期待 吗? 那就关注下面 公众号 随时锁定区块链开发学习教程进度 :)

区块链开发技术共享   野生极客

区块链开发 Go语言:并发编程

`

长按,识别二维码,加关注


孔壹CEO 黎跃春 区块链部落
长按,识别二维码,加关注



以上是关于区块链开发 Go语言:并发编程的主要内容,如果未能解决你的问题,请参考以下文章

区块链最全线上培训大纲——尹成学院

区块链开发之Go语言—文件系统

Go语言视频免费下载了!尚硅谷韩顺平老师再次发力!

GO语言凭什么是区块链的首选语言

区块链基础语言——Go语言工程管理

基于Go语言构建区块链:part1