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 ...
随机推荐
- UVa340 Master-Mind Hints
#include <stdio.h>#include <string.h> #define MIN(a,b) (((a) < (b)) ? (a) : (b)) int ...
- SignaLR通信技术
新建MVC项目 如果没有Signale需要使用NuGet安装Signalr namespace SignaLrDemo { public class ChatHub : Hub { public vo ...
- 简单的Coretext 图文混排
在很多新闻类或有文字展示的应用中现在都会出现图文混排的界面例如网易新闻等,乍一看去相似一个网页,其实这样效果并非由UIWebView 加载网页实现.现在分享一种比较简单的实现方式 iOS sdk中为我 ...
- python数据库连接
现在装python基本都内置了sqlite连接,写成如下形式即可 from sqlite3 import dbapi2 as sqlite 如果需要insert或update东西,之后的cur必须co ...
- eclipse编译错误
ERROR: JDWP Unable to get JNI 1.2 environment, jvm->GetEnv() return code = -2 JDWP exit error AGE ...
- PHP第一章学习——了解PHP(上)
计划开启PHP学习教程,情况如下: 1.采用教程35章48个视频文件 2.时间4月29日-5月6日 共计8天 3.具体划分每天学习章节数不少于5个,预留5-6号时间为五一假期出玩情况 4.要求认真学习 ...
- QQ聊天原理初识
1:qq之间文件的传输是通过p2p通信进行的. 2:qq之间的表情发送实际上就是文字的发送,是client再接受到文字之后在本地自己进行转换 3:qq之间的通信既能够通过udp也能够通过Tcp 尽管u ...
- String、StringBuffer、StringBuilder之间区别
String,StringBuffer,StringBuilder 之间区别 在字符串处理中C#提供了String.StringBuffer.StringBuilder三个类.那么他们到底有什么优缺点 ...
- asp.net中 服务器控件中onselectedindexchanged 没有反应的解决方案
最近发现项目中一个BUG就是 DropDownList 中的onselectedindexchanged 没有反应 AutoPostBack="true"和页面中的<%@ P ...
- .NET使用NPOI组件将数据导出Excel
.NPOI官方网站:http://npoi.codeplex.com/ 可以到此网站上去下载最新的NPOI组件版本 2.NPOI在线学习教程(中文版): http://www.cnblogs.com/ ...