如何在Golang HTTP服务器中定义全局计数器

I am newbie to GoLang and want to define a global counter in go-lang to record how many queries are made to the http server.

I think the simplest way is to define a 'global' variable that stored the current count, and increase it in every query (let's put the concurrence problem aside for convenient).

Any way, here is my code I planned to achieve this so far:

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)
}

As you can see, var count could not be defined there, It's vary from Java servlet which I formerly using.

So how can I achieve this?

Outside of functions you cannot use the short variable declaration :=. Outside of a function to define a global variable you have to use a variable declaration (with the var keyword):

var count int

It will automatically be initialized to int's zero value which is 0.

Links:

Relevant sections of the Go Language Specification which I recommend you to read:

Variable declarations

Short variable declarations

Note:

Since handling of each request runs in its own goroutine, you need explicit synchronization to access the shared counter, or you have to use other synchronized means to do a proper counting.

You may want to use standard way in golang that in expvar package for an example 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
", user)
    io.WriteString(w, msg)
}

func main() {
    http.HandleFunc("/", HelloServer)
    http.ListenAndServe(":8080", nil)
}

Beware that you might want to consider using the sync package, because counter = counter + 1 will skip one if it's called simultaneously.

The counter must be incremented atomically or else you will have race conditions and miss some counts.

Declare a global int64 variable and access it using the sync.atomic methods:

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))
}