这个是前段时间看到Go语言的贡献者与布道师 Dave Cheney对Go并发的建议或者叫使用的陷阱(不是我自己的建议),结合自己最近几年对gorotine的使用,再回头看这几条建议,真的会茅塞顿开,觉得特别重要。这篇文章对并发的建议的章节地址

https://dave.cheney.net/practical-go/presentations/qcon-china.html#_concurrency

Dave Cheney

Dave Cheney 是 Go 编程语言的开源贡献者和项目成员。David 是技术社区中备受尊敬的声音,他就软件设计、性能和 Go 编程语言等各种主题发表演讲。David 在go语言历程中,分享过很多关于Golang语言的正确使用的文章。这是他的博客地址。

https://dave.cheney.net/

8.1. Keep yourself busy or do the work yourself(让自己忙碌起来或自己做工作)

这个建议应该比较容易理解,启动一个gorotine应该是执行程序的,自己执行或者被人调用执行,不应该启动gorotine之后这个gorotine啥事都没干。

作者举了一个例子

package main

import (
"fmt"
"log"
"net/http"
) func main() {
http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
fmt.Fprintln(w, "Hello, GopherCon SG")
})
go func() {
if err := http.ListenAndServe(":8080", nil); err != nil {
log.Fatal(err)
}
}() for {
}
}

为了阻塞main gorotine不要直接退出,等待go func的执行,最后写了一个for的死循环,这样的话,main gorotine就是通常所说的啥事都没干,毫无结果地运行。我们当然可以使用WaitGroup去等待go func的结束。作者给我们的建议,既然我们只有一个任务需要做,main gorotine就可以完成,为什么要启动一个gorotine去做这个任务,而让main gorotine去等待,完全可以让main去做这个任务

import (
"fmt"
"log"
"net/http"
) func main() {
http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
fmt.Fprintln(w, "Hello, GopherCon SG")
})
if err := http.ListenAndServe(":8080", nil); err != nil {
log.Fatal(err)
}
}

许多 Go 程序员过度使用 goroutine,尤其是在他们刚开始的时候。与生活中的所有事物一样,适度是成功的关键。

8.2. Leave concurrency to the caller(将并发留给调用者)

这个表述起来比较容易,平常开发中可能会被忽略,一个对象提供了启动使用goroutine的方法,那么就必须提供关闭goroutine的方法,而且一般得原则的是谁调用谁关闭。

举一个我们项目开发中的例子

timer_go.go
package main import (
"fmt"
"sync"
"time"
) type TimerGo struct {
quit chan bool
} func NewTimerGo() *TimerGo {
timer := new(TimerGo)
timer.quit = make(chan bool)
return timer
} func (this *TimerGo) Run(wg *sync.WaitGroup) {
defer wg.Done()
cfgTime := 3 t := time.NewTicker(time.Duration(cfgTime) * time.Second)
defer t.Stop() for {
select {
case <- this.quit:
fmt.Println("quite")
return
case <-t.C:
this.Sync()
}
}
} func (this *TimerGo) Sync() {
fmt.Printf("Sync")
} func (this *TimerGo) Close() {
close(this.quit)
}
main.go
package main
func main() {
timergo := NewTimerGo()
wg := new(sync.WaitGroup)
wg.Add(1)
go timergo.Run(wg)
//start up
timergo.Close()
wg.Wait()
}

这个例子比较容易理解,我们需要每隔三秒执行一个异步的任务,这个工作我们启动一个goroutine去执行,所以我们在main函数执行go timergo.Run,我们也提供Close的方法,通过一个channal去关闭它。

原则就是,谁调用谁关闭。提供执行方法,就必须提供关闭方法。

8.3. Never start a goroutine without knowning when it will stop(永远不要在不知道何时停止的情况下启动 goroutine)

这个原则我觉得应该是最重要的原则,而且在开发中最容易遇到的问题。我们前期也写过很多这样的代码,而且我看大家使用的项目基本也都是在需要启动一个goroutine去执行代码的时候是这样写的

go AAA()
go BBB()
go CCC()

很少有人去关心启动的这三个goroutine应该在什么情况下去关闭,应该怎么关闭,他们得运行状态是怎么样的,在服务重新启动时候,是等待执行完毕还是强制中断。

这个原则应该会指引我们去做一些可靠的架构和规划。这个遇到的太多了,有必要花时间去整理这里。

永远不要在不知道何时停止的情况下启动 goroutine

golang开发:go并发的建议的更多相关文章

  1. golang开发:go并发的建议(完)

    上次说了一下Go语言布道师 Dave Cheney对Go并发的建议,个人觉得最重要的一条,这次主要想说一下这个. 8.3. Never start a goroutine without knowni ...

  2. 用golang开发系统软件的一些细节

    用golang开发系统软件的一些细节 作者:张富春(ahfuzhang),转载时请注明作者和引用链接,谢谢! cnblogs博客 zhihu Github 公众号:一本正经的瞎扯 (本文的pdf版本) ...

  3. window / Linux 下 Golang 开发环境的配置

    一直专注于使用python语言进行程序开发,但是却又一直被它的性能问题所困扰,直到遇到了天生支持高并发的Golang,这似乎也成了学习go语言最理所当然的理由.下面介绍下Go语言开发环境搭建的步骤: ...

  4. Golang开发支持平滑升级(优雅重启)的HTTP服务

    Golang开发支持平滑升级(优雅重启)的HTTP服务 - tabalt的博客 http://tabalt.net/blog/graceful-http-server-for-golang/ http ...

  5. Visual Studio Code配置GoLang开发环境

    Visual Studio Code配置GoLang开发环境 在Visual Studio Code配置GoLang开发环境 作者:chszs,未经博主允许不得转载.经许可的转载需注明作者和博客主页: ...

  6. Linux下配置Golang开发环境

    前几天无意间看到了微信推送的golang开发的消息,看到golang那么牛逼,突然心血来潮想学习一下go.工欲善其事必先利其器,想做go开发,必须先配置好go的开发环境(就像开发Java先安装配置jd ...

  7. [golang]Golang实现高并发的调度模型---MPG模式

    Golang实现高并发的调度模型---MPG模式 传统的并发形式:多线程共享内存,这也是Java.C#或者C++等语言中的多线程开发的常规方法,其实golang语言也支持这种传统模式,另外一种是Go语 ...

  8. Golang 开发技能图谱

    # Golang 开发技能图谱 ## Go 语言环境搭建- Go 安装- GOPATH 与工作空间- Go 命令- Go开发工具 ## GO 语言编程基础- 关键词和语法(Language Synta ...

  9. 关于Web开发里并发、同步、异步以及事件驱动编程的相关技术

    一.开篇语 我的上篇文章<关于如何提供Web服务端并发效率的异步编程技术>又成为了博客园里“编辑推荐”的文章,这是对我写博客很大的鼓励,也许是被推荐的原因很多童鞋在这篇文章里发表了评论,有 ...

随机推荐

  1. centos网卡配置修改

    centos网卡配置文件一般位于:/etc/sysconfig/network-scripts/ 文件名一般为:ifcfg-eno或者ifcfg-eth0类似的文件,可以先用ip addr 命令或者是 ...

  2. Unknown column ‘avatar_url‘ in ‘field list‘

    报错: Unknown column 'avatar_url' in 'field list' 解决: 查看mysql数据库中字段名前面是否有空格或则换行

  3. 浏览器输入URL,按下回车后发生什么?

    大致流程 URL 解析 DNS 查询 TCP 连接 服务器处理请求 浏览器接受响应 浏览器解析渲染页面 断开连接

  4. Python入门随记(1)

    1.IDE Interactive Development Enironment,交互式开发环境 2.AI artificial intelligence 3.Python是一种格式严明(严格缩进)的 ...

  5. path()的name属性,有什么用?

    官网(参考:命名 URL 模式) 命名 URL 模式: 为了完成反向解析 URL ,你需要像上面那样使用 命名 URL 模式 .用于命名 URL 的字符串可以包含任意字符,并不仅限于 Python 里 ...

  6. 【编程教室】Python绘制冬奥吉祥物“冰墩墩”

    大家好,欢迎来到 Crossin的编程教室 ! 这两天,随着北京冬奥会的开幕,吉祥物"冰墩墩"可是火出了圈,多少人排长队都买不到.据说甚至有人把价格炒到了几千元. 就连昨天的&qu ...

  7. 『现学现忘』Docker基础 — 35、实战:自定义CentOS镜像

    目录 1.前提说明 2.编写Dockerfile文件 3.构建镜像 4.运行镜像 5.列出镜像的变更历史 1)目标:自定义镜像wokong_centos. 2)所用到的保留字指令: FROM:基础镜像 ...

  8. java反射 java动态代理和cglib动态代理的区别

    java反射      https://blog.csdn.net/f2764052703/article/details/89311013 java 动态代理   https://blog.csdn ...

  9. python 面向对象的一些魔法方法和反射

    1.with和__enter__,__exit__,__init__配合使用class A: def __init__(self): print('init') def __enter__(self) ...

  10. 分布式HDFS的安装和启动(二)

    一.分布式HDFS的安装和启动①在$HADOOP_HOME/etc/hadoop/core-site.xml文件<property> <name>fs.defaultFS< ...