版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领
文档简介
Go语言的并发处理Go语言从入门到精通了解并发处理的基本概念与知识掌握Go语言中多任务的协同工作方式01CONCURENT02CONFLICT03TASKStarget目标掌握Go语言中避免并发共享冲突的主要方法目录导航11.1Go语言并发编程基础ContentsGo语言并发处理的优势
先天优势:是Go语言最重点解决的目标之一
极其简单便捷:一条语句启动线程
轻量级:轻松运行上千线程
语言级的并发支持:go关键字与通道(chan)数据类型硬件级支持:先天支持多核CPU上的调度简单的Goroutine启动方式func
function1()
{
a
:=
1
for
{
a++
fmt.Println(a)
}}
go
function1()
go关键字一条语句启动一个线程*
goroutine虽然与线程有所不同,但广义上我们还是可以称之为线程主线程func
main()
{
go
function1()
for
{ time.Sleep(100
*
time.Millisecond)
}
}main函数运行在主线程中主函数退出时,所有goroutine也将退出避免主线程占用过多CPU时间多核CPU并发分担cpuCores
:=
runtime.NumCPU()
//
获取实际CPU核数
runtime.GOMAXPROCS(2)
//
将可用CPU核数设为2目录导航11.2并发处理时的共享冲突Contents共享冲突var
valueG
int
=
0var
stop1
bool
=
falsevar
stop2
bool
=
false
func
routine1(countA
int,
stopA
*bool)
{
for
i
:=
0;
i
<
countA;
i++
{
valueG
=
valueG
+
2
}
*stopA
=
true}
func
main()
{
go
routine1(10000,
&stop1)
go
routine1(10000,
&stop2)
for
{
if
stop1
&&
stop2
{
break
}
}
fmt.Printf("valueG:
%v\n",
valueG)}多次运行结果不一致?并发安全共享安全就是保证在多任务并发处理时共享数据不会因共享冲突而导致错误需要在编程中加上控制机制来保证同一时刻只能由一个任务来访问该数据当变量或数据不会因多任务并发访问而出现异常时,我们就称之为是“共享安全”的目录导航11.3使用通道类型实现安全的数据共享Contents通道(chan)类型Go语言内置专门用于并发处理的数据类型:通道(chan)
chan类型可以理解成一个具备“共享安全”特性的“先入先出队列”*大多数其他语言是在标准库级别上支持线程的通道类型使用示例var
valueG
chan
intvar
stop1
bool
=
falsevar
stop2
bool
=
false
func
routine1(countA
int,
stopA
*bool)
{
for
i
:=
0;
i
<
countA;
i++
{
tmpC
:=
<-valueG
valueG
<-
(tmpC
+
2)
}
*stopA
=
true}
func
main()
{
valueG
=
make(chan
int,
1)
go
routine1(10000,
&stop1)
go
routine1(10000,
&stop2)
valueG
<-
0
for
{
if
stop1
&&
stop2
{
break
}
}
t.Printfln("valueG:
%v",
<-valueG)
close(valueG)注意->和<-操作符是“阻塞”的目录导航11.4使用通道类型实现安全的数据共享Contents通道类型使用示例var
tokenG
chan
boolvar
stop1
bool
=
falsevar
stop2
bool
=
false
func
routine1(countA
int,
stopA
*bool)
{
for
i
:=
0;
i
<
countA;
i++
{
<-tokenG
valueG
=
valueG
+
2
tokenG
<-
false
}
*stopA
=
true}
func
main()
{
tokenG
=
make(chan
bool,
1)
go
routine1(10000,
&stop1)
go
routine1(10000,
&stop2)
tokenG
<-
false
for
{
if
stop1
&&
stop2
{
break
}
}
t.Printfln("valueG:
%v",
valueG)
close(tokenG)获取到令牌的任务才能访问某些数据访问完毕之后交回令牌供其他任务使用目录导航11.5使用通道实现多任务的归并Contents多任务合并
并发编程中,主任务将任务拆分成子任务并等待所有子任务完成之后再进行下一步处理的过程称作“多任务的归并(或合并)”,英文中常用join来表示合并任务的主控线程//
调用多个addRoutine函数实现多goroutine计算累加和的函数//
将各个goroutine计算的结果之和加起来就是最终的总和func
addByGoroutine(countA
int)
float64
{
sumT
:=
0.0
//
lenT是每个goroutine需要计算的次数
lenT
:=
countA
/
goroutineCount
//
leftT是平均非给每个goroutine后还剩余需要计算的次数
leftT
:=
countA
-
(countA/goroutineCount)*goroutineCount
//
第一个goroutine将多计算leftT次,即lenT+leftT次
go
addRoutine(lenT
+
leftT)
//
其他goroutine将计算lenT次
for
i
:=
1;
i
<
goroutineCount;
i++
{
go
addRoutine(lenT)
}
//
从通道循环读取resultBuffer中的值,直到读满足够的个数
for
i
:=
0;
i
<
goroutineCount;
i++
{
sumT
+=
<-resultBuffer
}
//
返回最终的计算结果
return
sumT}此处将是阻塞地读取目录导航11.6用select实现多通道的归并Contents通过select监听多个通道//
调用多个addRoutine1函数和多个addRoutine2实现各自累加和并将两个累加和求相除结果的函数func
addByGoroutine(countA
int)
float64
{
sumT1
:=
0.0
sumT2
:=
0
lenT
:=
countA
/
goroutineCount//
lenT是每个goroutine需要计算的次数
leftT
:=
countA
-
(countA/goroutineCount)*goroutineCount
//
第一个goroutine将多计算leftT次,即lenT+leftT次
//
addRoutine1和addRoutine2都将被运行成同样个数的goroutine
go
addRoutine1(lenT
+
leftT)
go
addRoutine2(lenT
+
leftT)
for
i
:=
1;
i
<
goroutineCount;
i++
{//
其他goroutine将计算lenT次
go
addRoutine1(lenT)
go
addRoutine2(lenT)
}
//
从通道循环读取resultBuffer1或resultBuffer2中的值,直到读满足够的个数(应为2
*
goroutineCount个)
var
tmpF
float64
var
tmpC
int
for
i
:=
0;
i
<
goroutineCount*2;
i++
{
select
{
case
tmpF
=
<-resultBuffer1:
sumT1
+=
tmpF
case
tmpC
=
<-resultBuffer2:
sumT2
+=
tmpC
}
}
return
float64(sumT2)
/
sumT1//
返回最终的计算结果,为了计算类型一致,需要强制类型转换}尤其适合监听多个不同类型的通道时目录导航11.7select中实现超时中止Contents通过select监听多个通道
select
{
case
tmpF
=
<-resultBuffer1:
sumT1
+=
tmpF
case
tmpC
=
<-resultBuffer2:
sumT2
+=
tmpC
case
<-time.After(3
*
time.Second):
timeoutFlag
=
true
}time.After将返回一个定时触发的chan类型值目录导航11.8用单向通道自定义超时函数Contents单向通道var
c1
chan<-
int
//
定义一个只能写的通道
c1
=
make(chan<-
int,
10)
//
为只写通道设定容量//
直接简化式声明一个只读通道并设置容量
c2
:=
make(<-chan
float64,
10)
通过select监听多个通道//
休眠指定的秒数后,向通道中写入一个数值表示超时(数值本身不重要)//
chanA是只能写入的单向通道func
realTimeout1(secondsA
time.Duration,
chanA
chan<-
bool)
{
time.Sleep(secondsA
*
time.Second)
chanA
<-
true}
//
仅用于新建一个通道后启动真正的超时routine,并将该通道返回让select等待通道中有值func
timeout1(secondsA
time.Duration)
<-chan
bool
{
chan1
:=
make(chan
bool,
1)
//
传入realTimeout1的chan1被强制转换为只写通道类型
go
realTimeout1(secondsA,
(chan<-
bool)(chan1))
return
(<-chan
bool)(chan1)//
返回时将chan1强制转换为只读通道类型}…
select
{
case
tmpC
:=
<-resultBuffer1G:
totalSumT
+=
tmpC
case
tmpC
:=
<-resultBuffer2G:
totalSumT
+=
tmpC
case
<-timeout1(2):
//
超时时间是2秒
totalSumT
=
0
break
ForLabel
//
直接跳出循环而不是select结构
}是chan类型值就可以select目录导航11.9使用sync包进行传统的并发处理Contents用sync.WaitGroup实现goroutine归并var
groupG
sync.WaitGroup
func
addRoutine(countA
int)
{
defer
groupG.Done()
for
i
:=
0;
i
<
countA;
i++
{
valueG
=
valueG
+
2
}}
groupG.Add(2)
go
addRoutine(tim
温馨提示
- 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
- 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
- 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
- 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
- 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
- 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
- 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。
最新文档
- 二零二四年度出租车行业品牌推广协议
- 2024年度项目合作与投资合同模板
- 程序员2024年度团队协作协议
- 保密协议完整版
- 二零二四年度LED显示屏生产设备采购合同
- 2024年度电力传输合同标的:新建跨区域电力线路工程设计与施工
- 北京市二零二四年度广告代理合同
- 2024年度购物中心品牌特许经营合同
- 二零二四年度工程款结算与审计合同3篇
- 二零二四年度旅游业务合作与代理合同
- 幼儿园大班社会《伟大的起点 》 高清有声课件
- 【产学合作协同育人项目】实践条件和实践基地建设项目结题报告(含内容)(模板)
- 2.2《昼夜交替现象》课件
- 铁道工程专业职业生涯规划
- 地球与生命的进化课件
- 医德医风教育培训内容三篇
- 体育用品店行业市场分析研究报告-第3篇
- 中国旅游客源地和目的地概况PPT完整全套教学课件
- β内酰胺类抗菌药物皮肤试验指导原则(2021年版)解读
- 银行后备人才竞聘演讲稿
- 左宗棠课件完整版
评论
0/150
提交评论