我的程序运行正常,每次只有一个连接,但没有并发连接。
我需要一个函数呈现所有连接,这个函数将包含我服务中需要的所有数据,而且工作不正常,所以我用下面的简单代码说明:
package main
import (
"encoding/json"
"fmt"
"github.com/gorilla/mux"
"github.com/rs/cors"
"net/http"
"reflect"
"time"
)
var Out struct {
Code int `json:"status"`
Message []interface{} `json:"message"`
}
func Clear(v interface{}) {
p := reflect.ValueOf(v).Elem()
p.Set(reflect.Zero(p.Type()))
}
func YourHandler(w http.ResponseWriter, r *http.Request) {
Clear(&Out.Message)
Out.Code = 0
// w.Header().Set("Content-Type", "application/json; charset=UTF-8")
w.Header().Set("Access-Control-Allow-Origin", "*")
w.Header().Set("Access-Control-Allow-Headers","Content-Type,access-control-allow-origin, access-control-allow-headers")
w.WriteHeader(http.StatusOK)
for i:=0; i<10; i++ {
Out.Code = Out.Code + 1
Out.Message = append(Out.Message, "Running...")
time.Sleep(1000 * time.Millisecond)
if err := json.NewEncoder(w).Encode(Out)
err != nil {
http.Error(w, err.Error(), http.StatusInternalServerError)
}
}
}
func main() {
r := mux.NewRouter()
r.StrictSlash(true);
r.HandleFunc("/", YourHandler)
handler := cors.New(cors.Options{
AllowedOrigins: []string{"*"},
AllowCredentials: true,
Debug: true,
AllowedHeaders: []string{"Content-Type"},
AllowedMethods: []string{"GET"},
}).Handler(r)
fmt.Println("Working in localhost:5000")
http.ListenAndServe(":5000", handler)
}
如果你运行这段代码,你每次都不会在一个连接中看到任何错误,但是如果你在另一个tab / browser / etc中同时运行它,由于延迟,状态代码将不会从1到10,但是所有的电话都会被洗牌。
所以我猜这意味着它不是无状态的,我需要它,所以即使同时有300个连接,它也会始终从1到10返回状态代码。
我该怎么办? (正如我所说的,这是一个简单的代码,结构和渲染函数是彼此分开的包和所有数据集合中的)和/或
答案 0 :(得分:3)
net/http服务器同时调用处理程序。服务器为每个客户端连接创建一个goroutine,并在这些goroutine上调用处理程序。
Gorilla Mux在并发方面是被动的。在调用多路复用器的任何goroutine上,多路复用器调用已注册的应用程序处理程序。
使用sync.Mutex一次将执行限制为一个goroutine:
var mu sync.Mutex
func YourHandler(w http.ResponseWriter, r *http.Request) {
mu.Lock()
defer mu.Unlock()
Clear(&Out.Message)
Out.Code = 0
...
考虑到处理程序中的time.Sleep
调用,这不是一个好的解决方案。服务器每10秒最多处理一个请求。
更好的解决方案是将Out
声明为处理函数内的局部变量。通过此更改,此处不需要互斥锁或清除Out:
func YourHandler(w http.ResponseWriter, r *http.Request) {
var Out struct {
Code int `json:"status"`
Message []interface{} `json:"message"`
}
// w.Header().Set("Content-Type", "application/json; charset=UTF-8")
w.Header().Set("Access-Control-Allow-Origin", "*")
...
如果无法移动Out
的声明,则将值复制到局部变量:
func YourHandler(w http.ResponseWriter, r *http.Request) {
Out := Out // local Out is copy of package-level Out
Clear(&Out.Message)
Out.Code = 0
...
答案 1 :(得分:0)
Gorilla Mix使用Go的net / http服务器来处理您的http请求。 Go创建一个Go例程来为每个传入的请求提供服务。如果我正确理解您的问题,您希望Go响应将按照从1到10的顺序排列您的自定义状态代码,因为您希望每个请求按顺序同步进入。如果您熟悉Java,那么例行程序的并行性并不像Java线程那样保证执行顺序。因此,如果为1到10循环中创建的每个请求生成Go例程,则例程将自行执行,而不考虑先前完成的顺序。这些Go例程中的每一个都将在完成后为您的请求提供服务。如果要控制并行处理的这些请求的顺序,但按顺序则可以使用通道。查看此链接以控制每个http请求的10个Go例程之间的同步。 https://gobyexample.com/channel-synchronization
答案 2 :(得分:0)
首先,我要感谢ThunderCat和Ramil的帮助,你的答案给了我一个北方找到正确的答案。
简短的回答是:不要没有无国籍联系,所以我无法做我想要的事。
一旦说到,我认为(基于RFC 7230)它没有的原因是因为:
创建一个线程可以解决问题,但是Go没有它,而是有Goroutines,有关它的更多详细信息:
经过几天的努力和帮助,我将修复它,将我的结构改为键入并将其置于本地,如下所示:
package main
import (
"encoding/json"
"fmt"
"github.com/gorilla/mux"
"github.com/rs/cors"
"net/http"
"reflect"
"time"
)
type Out struct {
Code int `json:"status"`
Message []interface{} `json:"message"`
}
func Clear(v interface{}) {
p := reflect.ValueOf(v).Elem()
p.Set(reflect.Zero(p.Type()))
}
func YourHandler(w http.ResponseWriter, r *http.Request) {
localOut := Out{0,nil}
// w.Header().Set("Content-Type", "application/json; charset=UTF-8")
w.Header().Set("Access-Control-Allow-Origin", "*")
w.Header().Set("Access-Control-Allow-Headers","Content-Type,access-control-allow-origin, access-control-allow-headers")
w.WriteHeader(http.StatusOK)
for i:=0; i<10; i++ {
localOut.Code = localOut.Code + 1
localOut.Message = append(localOut.Message, "Running...")
time.Sleep(1000 * time.Millisecond)
if err := json.NewEncoder(w).Encode(localOut)
err != nil {
http.Error(w, err.Error(), http.StatusInternalServerError)
}
}
}
func main() {
r := mux.NewRouter()
r.StrictSlash(true);
r.HandleFunc("/", YourHandler)
handler := cors.New(cors.Options{
AllowedOrigins: []string{"*"},
AllowCredentials: true,
Debug: true,
AllowedHeaders: []string{"X-Session-Token","Content-Type"},
AllowedMethods: []string{"GET","POST","PUT","DELETE"},
}).Handler(r)
fmt.Println("Working in localhost:5000")
http.ListenAndServe(":5000", handler)
}
当然这需要几周时间,所以现在我把我的应用程序放在nginx后面,现在它按预期工作了。