如何在 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的相关章节:

Variable declarations

Short variable declarations

注:

由于每个请求的处理都在其自己的 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))
}