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 ...
随机推荐
- poj 3358
/** 大意: 给定小数(p/q),求其循环节的大小和循环节开始的位置 解法: 若出现循环 ai*2^m= aj%p; 即 2^m %p =1 若2与p 互素,则可由欧拉函数的, 不互素,需将其转化为 ...
- cocos2d-x Android环境搭建
1.Java虚拟机.分32位和64位.64位: jdk-8u11-windows-x64-8.0.11.12.1406275777 环境变量配置,我的电脑右击->属性->高级系统设置-&g ...
- 转: angularjs学习总结(~~很详细的教程)
1 前言 前端技术的发展是如此之快,各种优秀技术.优秀框架的出现简直让人目不暇接,紧跟时代潮流,学习掌握新知识自然是不敢怠慢. AngularJS是google在维护,其在国外已经十分火热,可是国内的 ...
- HDU 2067 小兔的棋盘
题解:卡特兰数的几何意义,所以答案就是卡特兰数的两倍 #include <cstdio> #include <iostream> using namespace std; #d ...
- VS2010/MFC:模态对话框及其弹出过程
模态对话框及其弹出过程 加法计算器对话框程序大家照着做一遍后,相信对基于对话框的程序有些了解了,有个好的开始对于以后的学习大有裨益.趁热打铁,这一节讲讲什么是模态对话框和非模态对话框,以及模态对话框怎 ...
- poj 1088 滑雪(区间dp+记忆化搜索)
题目链接:http://poj.org/problem?id=1088 思路分析: 1>状态定义:状态dp[i][j]表示在位置map[i][j]可以滑雪的最长区域长度: 2>状态转移方程 ...
- Asp.Net MVC4.0 官方教程 入门指南之三--添加一个视图
Asp.Net MVC4.0 官方教程 入门指南之三--添加一个视图 在本节中,您需要修改HelloWorldController类,从而使用视图模板文件,干净优雅的封装生成返回到客户端浏览器HTML ...
- 记一次排查log4net 不输出日志的解决过程
最近发现log4net 不输出日志了,重点排查几个地方,发现都没有问题. 1.[assembly: log4net.Config.XmlConfigurator(ConfigFile = " ...
- android四大组件详解--摘
Android四大基本组件介绍与生命周期 Android四大基本组件分别是Activity,Service服务,Content Provider内容提供者,BroadcastReceiver广播接收器 ...
- iOS开发之第三方登录微博-- 史上最全最新第三方登录微博方式实现
相关资源地址: 本项目demo地址 : https://github.com/zhonggaorong/weiboSDKDemo 最新SDK下载: 最新微博SDK 官网注册地址:点击打开链接 最新 ...