sync.Mutex或http.HandleFunc不起作用

huangapple go评论99阅读模式
英文:

sync.Mutex or http.HandleFunc not working

问题

我正在使用《The Go Programming Language》这本教材,其中介绍了如何使用Go创建一个Web服务器。

按照书中给出的代码,我创建了一个Web服务器:

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

然后,我想通过使用goroutine来测试自己的知识,所以我编写了一个程序,将调用服务器的端点"/rest" 1000次。

然后我调用了端点"/count",它应该返回之前端点被调用的次数。

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

问题是:"/count"端点返回的数字小于1000。请告诉我我做错了什么,或者我是否对sync.Mutex或http.HandleFunc()的工作原理有误解。

英文:

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 (
	&quot;fmt&quot;
	&quot;log&quot;
	&quot;net/http&quot;
	&quot;sync&quot;
)

var mu sync.Mutex
var count int

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

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

func counter(w http.ResponseWriter, r *http.Request) {
	mu.Lock()
	fmt.Fprintf(w, &quot;Count %d\n&quot;, 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 (
	&quot;fmt&quot;
	&quot;net/http&quot;
	&quot;os&quot;
	&quot;strconv&quot;
	&quot;io/ioutil&quot;
)

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

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

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

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.

答案1

得分: 2

互斥锁只能确保没有两个goroutine同时读写count然而它不能控制这些goroutine执行的顺序。

这意味着你的代码中没有任何东西能确保在执行http.Get(".../count")之前所有的go call()都已经完成。

如果你想在所有的go call()完成之后才执行http.Get(".../count"),你可以使用sync.WaitGroup来实现。

英文:

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(&quot;.../count&quot;) is executed.

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

答案2

得分: 0

sync.Mutexhttp.HandleFunc的工作正常,但每个处理程序都在自己的go协程中运行。无论它们被发布到服务器的顺序如何,都不能保证在调用count之前运行对handler任何调用。

在您的测试程序中,您可以在call()之前删除go关键字,这将确保所有请求按顺序运行,因为Get()等待服务器返回。或者,您可以使用评论中建议的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.

huangapple
  • 本文由 发表于 2021年8月21日 09:33:23
  • 转载请务必保留本文链接:https://go.coder-hub.com/68869478.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定