区块链开发 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语言:并发编程的主要内容,如果未能解决你的问题,请参考以下文章