如何在 golang http 服务器中定义一个全局计数器
How to define a global counter in golang http server
我是 GoLang 的新手并且
想在go-lang中定义一个全局计数器来记录对http服务器的查询次数。
我觉得最简单的方法就是定义一个'global'变量来存储当前计数,每次查询时增加它(为了方便先把并发问题放在一边)
无论如何,这是我目前计划实现的代码:
package main
import (
"fmt"
"net/http"
)
count := 0 // *Error* non-declaration statement outside function body
func increment() error{
count = count + 1
return nil
}
func mainHandler(w http.ResponseWriter, r *http.Request){
increment()
fmt.Fprint(w,count)
}
func main(){
http.HandleFunc("/", mainHandler)
http.ListenAndServe(":8085",nil)
}
如您所见,无法在那里定义 var count
,它与我以前使用的 Java servlet 不同。
那么我该如何实现呢?
在函数之外不能使用短变量声明 :=
。在定义全局变量的函数之外,您必须使用 variable declaration(使用 var
关键字):
var count int
它会自动初始化为int
的零值,即0
。
链接:
我推荐您阅读Go Language Specification的相关章节:
注:
由于每个请求的处理都在其自己的 goroutine 中运行,因此您需要显式同步才能访问共享计数器,或者您必须使用其他同步方式来进行适当的计数。
您可能想在 expvar
包中使用 golang 中的标准方式
例如 http://go-wise.blogspot.com/2011/10/expvar.html
package main
import (
"expvar"
"fmt"
"http"
"io"
)
// Two metrics, these are exposed by "magic" :)
// Number of calls to our server.
var numCalls = expvar.NewInt("num_calls")
// Last user.
var lastUser = expvar.NewString("last_user")
func HelloServer(w http.ResponseWriter, req *http.Request) {
user := req.FormValue("user")
// Update metrics
numCalls.Add(1)
lastUser.Set(user)
msg := fmt.Sprintf("G'day %s\n", user)
io.WriteString(w, msg)
}
func main() {
http.HandleFunc("/", HelloServer)
http.ListenAndServe(":8080", nil)
}
请注意,您可能需要考虑使用 sync
包,因为如果同时调用 counter = counter + 1
将跳过其中一个。
计数器必须以原子方式递增,否则您将遇到竞争条件并错过一些计数。
声明一个全局 int64
变量并使用 sync.atomic
方法访问它:
package main
import (
"net/http"
"sync/atomic"
)
var requests int64 = 0
// increments the number of requests and returns the new value
func incRequests() int64 {
return atomic.AddInt64(&requests, 1)
}
// returns the current value
func getRequests() int64 {
return atomic.LoadInt64(&requests)
}
func handler(w http.ResponseWriter, r *http.Request) {
incRequests()
// handle the request here ...
}
func main() {
http.HandleFunc("/", handler)
log.Fatal(http.ListenAndServe(":8080", nil))
}
我是 GoLang 的新手并且 想在go-lang中定义一个全局计数器来记录对http服务器的查询次数。
我觉得最简单的方法就是定义一个'global'变量来存储当前计数,每次查询时增加它(为了方便先把并发问题放在一边)
无论如何,这是我目前计划实现的代码:
package main
import (
"fmt"
"net/http"
)
count := 0 // *Error* non-declaration statement outside function body
func increment() error{
count = count + 1
return nil
}
func mainHandler(w http.ResponseWriter, r *http.Request){
increment()
fmt.Fprint(w,count)
}
func main(){
http.HandleFunc("/", mainHandler)
http.ListenAndServe(":8085",nil)
}
如您所见,无法在那里定义 var count
,它与我以前使用的 Java servlet 不同。
那么我该如何实现呢?
在函数之外不能使用短变量声明 :=
。在定义全局变量的函数之外,您必须使用 variable declaration(使用 var
关键字):
var count int
它会自动初始化为int
的零值,即0
。
链接:
我推荐您阅读Go Language Specification的相关章节:
注:
由于每个请求的处理都在其自己的 goroutine 中运行,因此您需要显式同步才能访问共享计数器,或者您必须使用其他同步方式来进行适当的计数。
您可能想在 expvar
包中使用 golang 中的标准方式
例如 http://go-wise.blogspot.com/2011/10/expvar.html
package main
import (
"expvar"
"fmt"
"http"
"io"
)
// Two metrics, these are exposed by "magic" :)
// Number of calls to our server.
var numCalls = expvar.NewInt("num_calls")
// Last user.
var lastUser = expvar.NewString("last_user")
func HelloServer(w http.ResponseWriter, req *http.Request) {
user := req.FormValue("user")
// Update metrics
numCalls.Add(1)
lastUser.Set(user)
msg := fmt.Sprintf("G'day %s\n", user)
io.WriteString(w, msg)
}
func main() {
http.HandleFunc("/", HelloServer)
http.ListenAndServe(":8080", nil)
}
请注意,您可能需要考虑使用 sync
包,因为如果同时调用 counter = counter + 1
将跳过其中一个。
计数器必须以原子方式递增,否则您将遇到竞争条件并错过一些计数。
声明一个全局 int64
变量并使用 sync.atomic
方法访问它:
package main
import (
"net/http"
"sync/atomic"
)
var requests int64 = 0
// increments the number of requests and returns the new value
func incRequests() int64 {
return atomic.AddInt64(&requests, 1)
}
// returns the current value
func getRequests() int64 {
return atomic.LoadInt64(&requests)
}
func handler(w http.ResponseWriter, r *http.Request) {
incRequests()
// handle the request here ...
}
func main() {
http.HandleFunc("/", handler)
log.Fatal(http.ListenAndServe(":8080", nil))
}