golang channel初次接触
goroutine之间的同步
goroutine是golang中在语言级别实现的轻量级线程,仅仅利用go就能立刻起一个新线程。多线程会引入线程之间的同步问题,经典的同步问题如生产者-消费者问题,在c,java级别需要使用锁、信号量进行共享资源的互斥使用和多线程之间的时序控制,而在golang中有channel作为同步的工具。
1. channel实现两个goroutine之间的通信
package main
import "strconv"
import "fmt"
func main() {
taskChan := make(chan string, 3)
doneChan := make(chan int, 1)
for i := 0; i < 3; i++ {
taskChan <- strconv.Itoa(i)
fmt.Println("send: ", i)
}
go func() {
for i := 0; i < 3; i++ {
task := <-taskChan
fmt.Println("received: ", task)
}
doneChan <- 1
}()
<-doneChan
}
- 创建一个channel,
make(chan TYPE {, NUM}), TYPE指的是channel中传输的数据类型,第二个参数是可选的,指的是channel的容量大小。 - 向channel传入数据,
CHAN <- DATA, CHAN指的是目的channel即收集数据的一方,DATA则是要传的数据。 - 启动一个goroutine接收main routine向channel发送的数据,
go func(){ BODY }()新建一个线程运行一个匿名函数。 - 从channel读取数据,
DATA := <-CHAN,和向channel传入数据相反,在数据输送箭头的右侧的是channel,形象地展现了数据从‘隧道’流出到变量里。 - 通知主线程任务执行结束,doneChan的作用是为了让main routine等待这个刚起的goroutine结束,这里显示了channel的另一个特性,如果从empty channel中读取数据,则会阻塞当前routine,直到有数据可以读取。
上面这个程序就是main routine向另一个routine发送了3条int类型的数据,当3条数据被接收到后,主线程也从阻塞状态恢复运行,随后结束。
2. 不要陷入“死锁”
我一开始用channel的时候有报过"fatal error: all goroutines are asleep - deadlock! "的错误,真实的代码是下面这样的:
package main
import "fmt"
func main() {
ch := make(chan int)
ch <- 1 // I'm blocked because there is no channel read yet.
fmt.Println("send")
go func() {
<-ch // I will never be called for the main routine is blocked!
fmt.Println("received")
}()
fmt.Println("over")
}
我的本意是从main routine发送给另一个routine一个int型的数据,但是运行出了上述的错误,原因有2个:
- 当前routine向channel发送/接收数据时,如果另一端没有相应地接收/发送,那么当前routine则会进行休眠。
- 这个程序的main routine先行在
ch <- 1进入休眠状态,程序的余下部分根本来不及运行,那么channel里的数据永远不会被读出,也就不能唤醒main routine,进入“死锁”。
解决这个“死锁”的方法可是是设置channel的容量大小大于1,那么channel就不会因为数据输入而阻塞主程; 或者将数据输入channel的语句置于启动新的goroutine之后。
3. channel作为状态转移的信号源
我跟着MIT的分布式计算课程做了原型为Map-Reduce的课后练习,目的是实现一个Master向Worker分派任务的功能:Master服务器去等待Worker服务器连接注册,Master先将Map任务和Reduce任务分派给这些注册Worker,等待Map任务全部完成,然后将Reduce任务再分配出去,等待全部完成。
// Initialize a channel which records the process of the map jobs.
mapJobChannel := make(chan string)
// Start a goroutine to send the nMap(the number of the Map jobs) tasks to the main routine.
go func() {
for m := 0; m < nMap; m++ {
// Send the "start a Map job <m>" to the receiver.
mapJobChannel <- "start, " + strconv.Itoa(m)
}
}()
// Main routine listens on this mapJobChannel for the Map job task information.
nMapJobs := nMap
// Process the nMap Map tasks util they're all done.
for nMapJobs > 0 {
// Receive the Map tasks from the channel.
taskInfo := strings.Split(<-mapJobChannel, ",")
state, mapNo := taskInfo[0], taskInfo[1]
if state == "start" {
// Assign a Map task with number mapNo to a worker.
go func() {
// Wait for a worker to finish the Map task.
ok, workNo := assignJobToWorker("Map", mapNo)
if ok {
// Send a task finish signal and set the worker's state to idle.
mapJobChannel <- "end, " + mapNo
setWorkerState(workNo, "idle")
} else {
// Restart this task and set the worker's state to finished.
mapJobChannel <- "start, " + mapNo
setWorkerState(workNo, "finished")
}
}()
} else {
nMapJobs--
}
}
以上是我截取自己写的代码,关于用channel来传递当前Map任务的进度信息,用类似信号的方式标注当前的任务执行状态。
- 当从channel中读取到"start, {NUM}"时找一个空闲的Worker去执行Map任务,并且等待它的完成,完成成功则向channel中发送"end, {NUM}"信号,表明任务完成,如果失败,就重发"start, {NUM}"信号。
- 从channel中读取到"end, {NUM}"时,把剩余任务数减1。
这种信号触发的方式,触发Master的状态转移,并且可以通过增加信号以及信号处理的方式,拓展业务处理的情况,暂时还能处理这个需求情景。
golang channel初次接触的更多相关文章
- 初次接触json...
这两天发现很多网站显示图片版块都用了瀑布流模式布局的:随着页面滚动条向下滚动,这种布局还会不断加载数据并附加至当前尾部.身为一个菜鸟级的程序员,而且以后可能会经常与网站打交道,我觉得我还是很有必要去尝 ...
- 初次接触GWT,知识点总括
初次接触GWT,知识点概括 前言 本人最近开始研究 GWT(Google Web Toolkit) ,现将个人的一点心得贴出来,希望对刚开始接触 GWT的程序员们有所帮助,也欢迎讨论,共同进步. 先说 ...
- [Docker]初次接触
Docker 初次接触 近期看了不少docker介绍性文章,也听了不少公开课,于是今天去官网逛了逛,发现了一个交互式的小教程于是决定跟着学习下. 仅仅是把认为重点的知识记录下来,不是非常系统的学习和笔 ...
- 初次接触:DirectDraw
第六章 初次接触:DirectDraw 本章,你将初次接触DirectX中最重要的组件:DirectDraw.DirectDraw可能是DirectX中最强大的技术,因为其贯穿着2D图形绘制同时其帧缓 ...
- golang channel的使用以及调度原理
golang channel的使用以及调度原理 为了并发的goroutines之间的通讯,golang使用了管道channel. 可以通过一个goroutines向channel发送数据,然后从另一个 ...
- 初次接触scrapy框架
初次接触这个框架,先订个小目标,抓取QQ首页,然后存入记事本. 安装框架(http://scrapy-chs.readthedocs.io/zh_CN/0.24/intro/install.html) ...
- javaweb中的乱码问题(初次接触时写)
javaweb中的乱码问题 在初次接触javaweb中就遇到了乱码问题,下面是我遇到这些问题的解决办法 1. 页面乱码(jsp) 1. 在页面最前方加上 <%@ page language=&q ...
- 初次接触Java
今天初次接触Eclipse,学着用他来建立java工程,话不多说,来看看今天的成果! 熟悉自己手中的开发工具,热热身 刚上手别慌,有问题找度娘 刚刚拿到这个软件的安装包我是一脸懵逼的,因为是从官网下载 ...
- -1.记libgdx初次接触
学习一门技术最难的是开发环境变量配置和工具配置,以下为我初次接触libgdx时遇到的问题 几个难点记录下 gradle 直接用下到本地,然后放到d盘,链接到就行(gradle-wrapper.prop ...
随机推荐
- Problem C Andy's First Dictionary(set的使用)
题目链接:Problem C 题意:输入一个文本,找出所有不同的单词,按照字典序从小到大输出,单词不区分大小写. 思路:将字母序列都存为小写,非字母的字符变成空格,然后利用stringstream实现 ...
- libuv 错误号UV_ECANCELED 的处理
这个地方有好多的不明白,也没仔细的看懂代码,希望有牛人指点. 先记录几个issue 1. after_write recv many(>10000) ECANCELED in my write_ ...
- SQL Server 取前一天的0点和23点59分59秒
DECLARE @startDate1 DATE; DECLARE @startDate DATETIME; ,@startDate1); ,CONVERT(DATETIME,@startDate1) ...
- DB2 VC++ 中连接字符串
根据你安装的驱动,有如下两种连接字符串形式.Provider=DB2OLEDB;Network Transport Library=TCPIP;Network Address=xxx.xxx.xxx. ...
- 10.PHP 教程_PHP If...Else 语句
条件语句用于根据不同条件执行不同动作. PHP 条件语句 当您编写代码时,您常常需要为不同的判断执行不同的动作.您可以在代码中使用条件语句来完成此任务. 在 PHP 中,提供了下列条件语句: if 语 ...
- 关于appcompat v7出现的问题
一.问题描述: 新建了一个MIN-SDK为API 8的工程之后,TARGET-SDK为API 17的Android工程之后,自动生成的appcompat v7会提示“v7/value21:no res ...
- jQuery validate和form插件配套使用
参考 官网http://jqueryvalidation.org/documentation/ 博客http://www.cnblogs.com/buzzlight/archive/2010/06/3 ...
- 射频识别技术漫谈(9)——动物标签HDX
半双工(HDX,Half Duplex)技术是ISO11784/11785中规定的另一种标签与读写器之间的通讯方式.读写器先打开射频场对标签充电以激活标签,然后关闭磁场,标签在读写器磁场关闭的情况下向 ...
- HDU1181【有向图的传递闭包】
题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=1181 题意很简单. 有用并查集做的.我这里用传递闭包做. 有向图的传递闭包采用Floyd思想,可以判断 ...
- ASP.net体系