sync.Mutex or http.HandleFunc not working

Viewed 545

I am using the textbook: "The Go Programming Language" and in it they show how to make a webserver using Go.

Following the code they give, I made a webserver:

package main

import (
    "fmt"
    "log"
    "net/http"
    "sync"
)

var mu sync.Mutex
var count int

func main() {
    http.HandleFunc("/", handler)
    http.HandleFunc("/count", counter)
    log.Fatal(http.ListenAndServe("localhost:8080", nil))
}

func handler(w http.ResponseWriter, r *http.Request) {
    mu.Lock()
    count++
    mu.Unlock()
    fmt.Fprintf(w, "URL.Path = %q\n", r.URL.Path)
}

func counter(w http.ResponseWriter, r *http.Request) {
    mu.Lock()
    fmt.Fprintf(w, "Count %d\n", count)
    mu.Unlock()
}

Afterwards I wanted to test my knowledge with goroutines so I made a program that will call the server endpoint: "/rest" 1000 times.

Then I call the endpoint: "/count" which is suppose to return the amount of times the previous endpoint was called.

send.go

package main

import (
    "fmt"
    "net/http"
    "os"
    "strconv"
    "io/ioutil"
)

func main() {
    times, _ := strconv.Atoi(os.Args[1])
    
    for i := 0; i < times; i++ {
        go call()
    }

    response, err := http.Get("http://localhost:8080/count")
    if err != nil {
        fmt.Println("ERROR ", err)
    }
    
    text, _ := ioutil.ReadAll(response.Body)
    fmt.Println(string(text))
    response.Body.Close()
}

func call() {
    _, _= http.Get("http://localhost:8080/rest")
}

The problem is this: the /count endpoint returns a number less than 1000. Please tell me what I am doing wrong, or if there is I'm misunderstanding about how sync.Mutex or http.HandleFunc() works.

2 Answers

The mutex only ensures that no two goroutines will write/read count at the same time, however it does not control the order in which those goroutines are executed.

That means that there is nothing in your code that ensures that all of the go call() are finished before http.Get(".../count") is executed.

If you want to execute http.Get(".../count") only after all of the go call() are finished, then you can do that by using a sync.WaitGroup.

sync.Mutex and http.HandleFunc are working as they should, but every handler is run in it's own go-routine. There is no guarantee that any call to handler is run before the call to count irrespective of the order they are posted to the server.

In your test program you can remove the go keyword before call() which will ensure that all the requests are run in series, since Get() waits for a return from the server. Or you could use the WaitGroup as suggested in the comments which would allow the requests to be processed in parallel but wait for them all to finish before sending the count request.

Related