Golang笔记——并发
o语言中的main函数也是运行在一个单独的goroutine中的,一般称为 main goroutine,main函数结束时,会打断其它 goroutine 的执行,但是其它 goroutine 不会打断其它的 goroutine 的执行,除非是通过通信让对方自行中止。
先来看一个最简单的并发例子,一个时间服务器:(偏题了,不应该使用这个例子,应该突出重点,这个例子可以放到tcp那节)
func main() {
listener, err := net.Listen("tcp", "localhost:8000") if err != nil {
log.Fatal(err)
}
for {
conn, err := listener.Accept() if err != nil {
log.Print(err)
continue
}
go handleConn(conn)
}
}
func handleConn(c net.Conn) {
defer c.Close() for {
_, err := io.WriteString(c, time.Now().Format("2006/01/02 15:04:05n")) if err != nil { return
}
time.Sleep(1 * time.Second)
}
}
从这个例子可以看出,使用go开启一个tcp服务非常简洁,此外从该例子中,我们可以顺便了解一下go中格式化日期和时间的方式是非常奇葩的,格式化模板限定为Mon Jan 2 03:04:05PM 2006 UTC-0700,可以这样记:1月2日下午3点4分5秒(200)6年UTC-0700。
可以用 nc 或 telnet 来连接这个tcp服务进行测试, 也可以使用go实现一个简单的客户端:
func main() {
conn, err := net.Dial("tcp", "localhost:8000") if err != nil {
log.Fatal(err)
}
defer conn.Close()
mustCopy(os.Stdout, conn)
}
func mustCopy(dst io.Writer, src io.Reader) { if _, err := io.Copy(dst, src); err != nil {
log.Fatal(err)
}
}
goroutine是通过 channel 来通信的, 包括发送和接收两种操作。可以通过 make 来声明一个channel 如 ch = make(chan int),和 map 类似,channel 也只是对应底层数据结构的引用,所以发送方和接收方都将引用同一份对象,channel是引用类型,所以它的零值是 nil。channel 使用的操作符是 <- ,发送操作是指将数据发送到 channel,接收是指从 channel中接收。channel类似于一般的io系统,可以通过 close(ch) 来关闭一个 channel,关闭后,将不能进行发送操作,但可以接收之前未接收完的数据,如果没有数据可接收,则接收到一个nil。
通过 make(chan int) 这种方式创建的 channel 称之为无缓存channel,表示 channel的容量是0,如果要声明一个有缓存的channel,可以使用 make(chan int, 100) ,第二个参数表示初始化时的channel容量大小。
一个基于无缓存Channels的发送操作将导致发送者goroutine阻塞,直到另一个goroutine在相同的Channels上执行接收操作,当发送的值通过Channels成功传输之后,两个goroutine可以继续执行后面的语句。反之,如果接收操作先发生,那么接收者goroutine也将阻塞,直到有另一个goroutine在相同的Channels上执行发送操作。
简单的说,就是使用无缓存channel时,一旦通信发起,必须要等到通信完成才可以继续执行,否则将阻塞等待。这也就意味着,无缓存channel在通信时,会强制进行一次同步操作,所以无缓存channel也称之为同步channel
- 没有event loop的PHP
- RestTemplate的逆袭之路,从发送请求到负载均衡
- limit_area_cirle
- Spring RestTemplate中几种常见的请求方式
- 什么是客户端负载均衡
- jQuery 升级踩坑大全
- Eureka中的核心概念
- Spring Cloud Zuul中异常处理细节
- Spring Cloud Zuul中路由配置细节
- Spring Cloud中的API网关服务Zuul
- MYSQL | 企业整合解决方案之mysql集群搭建-主从配置
- Spring Cloud中Feign配置详解
- Spring Cloud中Feign的继承特性
- JavaScript 常用方法总结
- JavaScript 教程
- JavaScript 编辑工具
- JavaScript 与HTML
- JavaScript 与Java
- JavaScript 数据结构
- JavaScript 基本数据类型
- JavaScript 特殊数据类型
- JavaScript 运算符
- JavaScript typeof 运算符
- JavaScript 表达式
- JavaScript 类型转换
- JavaScript 基本语法
- JavaScript 注释
- Javascript 基本处理流程
- Javascript 选择结构
- Javascript if 语句
- Javascript if 语句的嵌套
- Javascript switch 语句
- Javascript 循环结构
- Javascript 循环结构实例
- Javascript 跳转语句
- Javascript 控制语句总结
- Javascript 函数介绍
- Javascript 函数的定义
- Javascript 函数调用
- Javascript 几种特殊的函数
- JavaScript 内置函数简介
- Javascript eval() 函数
- Javascript isFinite() 函数
- Javascript isNaN() 函数
- parseInt() 与 parseFloat()
- escape() 与 unescape()
- Javascript 字符串介绍
- Javascript length属性
- javascript 字符串函数
- Javascript 日期对象简介
- Javascript 日期对象用途
- Date 对象属性和方法
- Javascript 数组是什么
- Javascript 创建数组
- Javascript 数组赋值与取值
- Javascript 数组属性和方法
- 谈谈 Java 中自定义注解及使用场景
- SSM 单体框架 - 教育平台后台管理系统:视频讲解
- Day19.python时间和日期
- Kafka重要知识点之消费组概念
- Day15.异常的处理
- 「翻译」在生物信息学中使用 GNU-Parallel
- Kafka运维小贴士 | Kafka 消息监控
- MySQL慢查询优化 | 联结原理
- MySQL千万大表优化实践
- GitHub 标星过万!计算机与网络知识总结电子书下载!
- 盘一盘,那些提效/创意的 vscode 插件
- 基于jenkins实现手动拉取码云代码,实现半自动化部署
- so easy!网页骨架屏自动生成方案(dps)
- 深夜,我偷听到程序员要对session下手……
- CAM 系列论文阅读总结