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
- 【机器学习】我在面试机器学习、大数据岗位时遇到的各种问题
- 【机器学习】机器学习编程语言之争狼烟再起,Python称霸?
- TiDB 1.1 Beta Release
- 【Python环境】Python面试题汇总(二)
- 【Python环境】Python性能优化的20条建议
- 【Python环境】Python面试题汇总(一)
- 如何优雅的编写Dockerfile
- 【干货】找不到适合自己的编程书?我自己动手写了一个热门编程书搜索网站(附PDF书单)
- Docker监控方案(TIG)的研究与实践之Influxdb
- Docker监控方案(TIG)的研究与实践之Telegraf
- 【自然框架】之通用权限(九):权限的验证
- 【自然框架】之通用权限(八):权限到字段(列表、表单、查询)
- 【自然框架】之通用权限(七):权限到按钮
- 通过预测API窃取机器学习模型
- 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 数组属性和方法
- 测试面试题集锦(三)| 计算机网络和数据库篇(附答案)
- 关于Scikit-Learn你(也许)不知道的10件事
- 技术天地 | CSS-in-JS:一个充满争议的技术方案
- 安全研究 | 通过域名劫持实现Azure DevOps账户劫持
- 一款针对DLL劫持的恶意DLL生成器
- AuthMatrix:一款针对Web应用和服务的认证安全检测BurpSuite工具
- KITT-Lite:基于Python实现的轻量级命令行渗透测试工具集
- 一次KimSuky攻击事件分析
- OpenCV中如何使用滚动条动态调整参数
- 一文读懂「分布式架构」
- 老哥,您看我这篇Java集合,还有机会评优吗?
- 在 IDEA 中使用 Java 热部署插件 JRebel
- 后端必备 Git 分支开发:规范指南
- 大量的 TIME_WAIT 状态连接怎么处理?(文末有福利)
- 线上教育系统开发中,购物车功能是如何实现的?