3 回答
TA贡献1878条经验 获得超4个赞
是的,如果我不阻止它,你的观点“c) 是正确的” 。
为了保存响应编写器,您不应该在其中调用 go routine。相反,您应该将ServeHTTP作为 go-routine 调用,大多数 http 服务器实现都这样做。
这样你就不会阻止任何 api 调用,每个 api 调用将在不同的 go-routine 中运行,被它们的功能阻止。
由于您的“jobs chan QueueElement”是单个通道(不是缓冲通道),因此您的所有进程都在“gv.jobs <- newPrintJob”处被阻塞。
您应该使用缓冲通道,以便所有 api 调用都可以将其添加到队列中并根据工作完成或超时获得响应。
拥有缓冲通道也可以模拟打印机在现实世界中的内存限制。(队列长度 1 是特例)
TA贡献1817条经验 获得超6个赞
我已经为您的代码添加了一些更新。现在它像你描述的那样工作。
package main
import (
"database/sql"
"fmt"
"log"
"math/rand"
"net/http"
"sync"
"time"
)
type QueueElement struct {
jobid string
rw http.ResponseWriter
doneChan chan struct{}
}
type GlobalVars struct {
db *sql.DB
wg sync.WaitGroup
jobs chan QueueElement
}
func (gv *GlobalVars) ServeHTTP(w http.ResponseWriter, r *http.Request) {
switch r.URL.Path {
case "/StartJob":
fmt.Printf("incoming\r\n")
doneC := make(chan struct{}, 1) //Buffered channel in order not to block the worker routine
go func(doneChan chan struct{}, w http.ResponseWriter) {
gv.jobs <- QueueElement{
doneChan: doneC,
jobid: "jobid",
}
}(doneC, w)
select {
case <-time.Tick(time.Second * 5):
fmt.Fprintf(w, "job is taking more than 5 seconds to complete\r\n")
fmt.Printf("took longer than 5 secs\r\n")
case <-doneC:
fmt.Fprintf(w, "instant reply from serveHTTP\r\n")
fmt.Printf("instant\r\n")
}
default:
fmt.Fprintf(w, "No such Api")
}
}
func worker(jobs <-chan QueueElement) {
for {
job := <-jobs
fmt.Println("START /i /b try.cmd")
fmt.Printf("job done")
randTimeDuration := time.Second * time.Duration(rand.Intn(7))
time.Sleep(randTimeDuration)
// processExec("START /i /b processAndPrint.exe -" + job.jobid)
job.doneChan <- struct{}{}
}
}
func main() {
// create a GlobalVars instance
gv := GlobalVars{
//db: db,
jobs: make(chan QueueElement),
}
go worker(gv.jobs)
// create an http.Server instance and specify our job manager as
// the handler for requests.
server := http.Server{
Handler: &gv,
Addr: ":8888",
}
// start server and accept connections.
log.Fatal(server.ListenAndServe())
}
- 3 回答
- 0 关注
- 118 浏览
添加回答
举报