golang

热重启golang服务器(graceful restart golang http server)

懵懂的女人 提交于 2020-03-04 20:09:45
原文: 热重启golang服务器(graceful restart golang http server) 服务端代码经常需要升级,对于线上系统的升级常用的做法是,通过前端的负载均衡(如nginx)来保证升级时至少有一个服务可用,依次(灰度)升级。 而另一种更方便的方法是在应用上做热重启,直接升级应用而不停服务。 原理 热重启的原理非常简单,但是涉及到一些系统调用以及父子进程之间文件句柄的传递等等细节比较多。 处理过程分为以下几个步骤: 监听信号(USR2) 收到信号时fork子进程(使用相同的启动命令),将服务监听的socket文件描述符传递给子进程 子进程监听父进程的socket,这个时候父进程和子进程都可以接收请求 子进程启动成功之后,父进程停止接收新的连接,等待旧连接处理完成(或超时) 父进程退出,升级完成 细节 父进程将socket文件描述符传递给子进程可以通过命令行,或者环境变量等 子进程启动时使用和父进程一样的命令行,对于golang来说用更新的可执行程序覆盖旧程序 server.Shutdown()优雅关闭方法是go1.8的新特性 server.Serve(l)方法在Shutdown时立即返回,Shutdown方法则阻塞至context完成,所以Shutdown的方法要写在主goroutine中 代码 代码部分加了些注释 package main import (

GoLang之错误处理

不羁的心 提交于 2020-03-04 19:11:01
错误处理 error Go语言引入了一个错误处理的标准模式,即error接口,该接口定义如下: type error interface { Error() string } 对于大多数函数,如果要返回错误,可以将error作为多返回值的最后一个: func foo(param int)(ret int, err error) { ... } 调用时的代码: n, err := foo(0) if err != nil { // 错误处理 } else { // 使用返回值n } 我们还可以自定义错误类型,一个例子: package main import "fmt" import "errors" //自定义的出错结构 type myError struct { arg int errMsg string } //实现Error接口 func (e *myError) Error() string { return fmt.Sprintf("%d - %s", e.arg, e.errMsg) } //两种出错 func error_test(arg int) (int, error) { if arg < 0 { return -1, errors.New("Bad Arguments - negtive!") }else if arg >256 { return -1,

golang基础--细说defer

走远了吗. 提交于 2020-03-04 19:09:39
defer 匿名函数特性 执行方式类似其它语言中的析构函数,在函数体执行结束后按照调用顺序的 相反顺序 逐个执行 //执行顺序相反 package main import "fmt" func main() { fmt.Println("a") defer fmt.Println("b") defer fmt.Println("c") } /*输出 a c b */ 即使函数发生 严重的错误 也会执行,类似于try...except 常用于 资源清理,文件关闭,解锁以及记录时间等操作 支持匿名函数的调用 通过于匿名函数配合可在return之后修改函数计算的结果 -如果函数体内某个变量作为defer时匿名函数的参数,则在定义defer时即已经获得了拷贝,否则 则时引用某个变量的地址 //支持匿名函数 package main import "fmt" func main() { for i := 0; i < 3; i++ { defer func() { //函数体内的变量传递到defer匿名函数 fmt.Println(i) //此时引用的时变量i的地址 }() } } /*输出 3 3 3 */ Go没有异常机制,但有panic/recover模式来处理错误 Panic可以在任何地方引发 panic错误机制 //panic 错误机制,遇到panic语句后,后面不会再执行

Golang 笔记 4 defer、error、panic

百般思念 提交于 2020-03-04 19:05:38
一、defer语句 defer语句仅能被放置在函数或方法中。它由关键字defer和一个调用表达式组成。这里的表达式所表示的既不能是对Go语言内建函数的调用也不能是对Go语言标准库代码包unsafe中的那些函数的调用。实际上,满足上述条件的表达式被称为表达式语句。例: func readFile(path string) ([]byte, error) { file,err != os.Open(path) if err != nil { return nil,err } defer file.Close() return ioutil.ReadAll(file) } 函数readFile的功能是读取指定文件或目录本身的内容并将其返回,同时当有错误发生时立即向调用方报告。其中os和ioutil代表的都是Go语言标准库中的代码包。在打开文件且未发现有错误发生之后,紧跟了一条defer语句。其中携带的表达式语句表示的是对被打开文件的关闭操作。当这条defer语句被执行的时候,其中的这条表达式语句并不会被执行。它的确切的执行时机是在其所属的函数(这里是readFile)的执行即将结束的那个时刻。也就是说,在readFile函数真正结束执行的前一刻,file.Close()才会被执行。该语句可保证在readFile函数将结果返回给调用方之前,那个文件或目录一定会被关闭。

golang 详解defer

旧街凉风 提交于 2020-03-04 19:02:48
什么是defer defer用来声明一个延迟函数,把这个函数放入到一个栈上, 当外部的包含方法return之前,返回参数到调用方法之前调用,也可以说是运行到最外层方法体的"}"时调用。我们经常用他来做一些 资源的释放 ,比如关闭io操作 func doSomething(fileName string) { file,err := os.Open(fileName) if err != nil { panic(err) } defer file.Close() } defer 可以保证方法可以在外围函数返回之前调用。有点像其他言的 try finally try{ }finally{ } defer 读写外部变量   defer声明的函数读写外部变量,和闭包差不多。比如下面的代码 func doSomething() { v := 10 defer func() { fmt.Println(v) v++ fmt.Println(v) }() v += 5 } 输出为 15 16   就像闭包一样,如果不是defer函数方法内的变量会向上一层函数访问变量,重新做计算。 defer 读写命名的返回值 这个例子中,defer声明的方法,给命名的返回值自增1 1 func doSomething() (rev int) { 2 defer func() { 3 rev++ 4 }() 5

拒绝滥用golang defer机制

帅比萌擦擦* 提交于 2020-03-04 18:50:44
原文链接 : http://www.bugclosed.com/post/17 defer机制 go语言中的defer提供了在函数返回前执行操作的机制,在需要资源回收的场景非常方便易用(比如文件关闭,socket链接资源十分,数据库回话关闭回收等),在定义资源的地方就可以设置好资源的操作,代码放在一起,减小忘记引起内存泄漏的可能。 defer机制虽然好用,但却不是免费的,首先性能会比直接函数调用差很多;其次,defer机制中返回值求值也是一个容易出错的地方。 一个简单的性能对比测试 通过一个对锁机制的defer操作来比较性能差异。 package main import ( "sync" "testing" ) var ( lock = new(sync.Mutex) ) func lockTest() { lock.Lock() lock.Unlock() } func lockDeferTest() { lock.Lock() defer lock.Unlock() } func BenchmarkTest(b *testing.B) { for i := 0; i < b.N; i++ { lockTest() } } func BenchmarkTestDefer(b *testing.B) { for i := 0; i < b.N; i++ {

golang 快速排序

断了今生、忘了曾经 提交于 2020-03-03 22:00:14
golang 快速排序 package main import ( "fmt" "strconv" ) func quickSort(arr []int, low, high int) { if low < high { var pivot = partition(arr, low, high) quickSort(arr, low, pivot) quickSort(arr, pivot + 1, high) } } func partition(arr []int,low,high int) int { var pivot = arr[low] var i = low var j= high // 6 5 4 3 2 1 // 6 1 2 3 4 7 for i< j{ for arr[j] >= pivot && j > low { j-- } // for arr[i]<= pivot && i<high{ i++ } if i<j { arr[i],arr[j]=arr[j],arr[i] } } arr[low],arr[j] = arr[j],pivot // return j } func printArray(arr []int) { for i := 0; i < len(arr); i++ { fmt.Print(strconv.Itoa(arr[i]) +

golang模块viper读取配置文件

ぃ、小莉子 提交于 2020-03-03 21:13:04
一、介绍 Viper是一个方便Go语言应用程序处理配置信息的库。它可以处理多种格式的配置。它支持的特性: 设置默认值 从JSON、TOML、YAML、HCL和Java properties文件中读取配置数据 可以监视配置文件的变动、重新读取配置文件 从环境变量中读取配置数据 从远端配置系统中读取数据,并监视它们(比如etcd、Consul) 从命令参数中读物配置 从buffer中读取 调用函数设置配置信息 简单的设置默认值 viper.SetDefault("time", "2019-7-14") viper.SetDefault("notifyList", []string{"maple","ffm"}) 监视配置文件,重新读取配置数据 package main import ( "fmt" "github.com/fsnotify/fsnotify" "github.com/spf13/viper" ) viper:=viper.New() viper.WatchConfig() viper.OnConfigChange(func(e fsnotify.Event) { fmt.Println("Config file changed:", e.Name) }) 二、读取config.json #json文件 { "appId": "123456789", "secret":

golang中的内存逃逸

自闭症网瘾萝莉.ら 提交于 2020-03-03 15:28:13
关于golang的变量是定义在堆上还是栈上,官方的解释如下 How do I know whether a variable is allocated on the heap or the stack? From a correctness standpoint, you don't need to know. Each variable in Go exists as long as there are references to it. The storage location chosen by the implementation is irrelevant to the semantics of the language. The storage location does have an effect on writing efficient programs. When possible, the Go compilers will allocate variables that are local to a function in that function's stack frame. However, if the compiler cannot prove that the variable is not referenced after the

【原创翻译】如何命名变量

感情迁移 提交于 2020-03-03 00:48:28
恰当地命名变量,是软件开发的重要组成部分。变量名称必须由字母开头,其后可以含有字母、数字和_(下划线)。Go编译器并不关注你怎么命名变量,它的命名方式只对你(或其他人)有意义。尽可能地选择贴近变量含义的名称。假设有如下代码: x := "Max" fmt.Println("My dog's name is", x) 在这个例子中,x不是一个很好的变量名称。更好的名称也许是: name := "Max" fmt.Println("My dog's name is", name) 甚至: dogsName := "Max" fmt.Println("My dog's name is", dogsName) 在最后一个例子中,我们利用了“驼峰式”变量名来连接多个单词。第一个单词的首字母是小写,其后单词的首字母是大写,其他所有字母都是小写。 原文地址: http://www.zingscript.com/translate/golang-book 来源: oschina 链接: https://my.oschina.net/u/1441707/blog/196173