亚洲在线久爱草,狠狠天天香蕉网,天天搞日日干久草,伊人亚洲日本欧美

為了賬號安全,請及時綁定郵箱和手機立即綁定
已解決430363個問題,去搜搜看,總會有你想問的

后臺打印程序概念/API 和通道:將作業從 serveHTTP 傳遞到隊列

后臺打印程序概念/API 和通道:將作業從 serveHTTP 傳遞到隊列

Go
慕妹3146593 2023-06-19 17:38:31
在這里已經得到了一些幫助,這讓我在我正在嘗試的這個概念上取得了進展,但它仍然不太奏效,我遇到了一個我似乎無法解決的沖突。我在這里嘗試在流程圖中說明我想要的內容 - 請注意,客戶端可以是許多將發送 printjobs 的客戶端,因此我們無法回復工作人員當時正在處理我們的工作,但對于大多數情況而言(高峰時間不會,因為打印的處理工作可能需要時間)。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            newPrintJob := QueueElement{                    doneChan: doneC,                        jobid:    "jobid",            }上面的代碼是 serveHTTP 和 worker 的幫助,最初 ServeHTTP 中的 func 是一個 go 例程,在這里對我來說整個沖突都出現了 - 這個概念是在 serveHTTP 中它產生一個將得到回復的進程如果工人能夠在 5 秒內及時處理作業,則從工人處獲得。如果工作能夠在 1 秒內完成,我想在 1 秒后立即回復客戶,如果需要 3 秒,我想在 3 秒后回復,如果超過 5 秒,我會在 5 秒后回復(如果工作需要 13 秒,我仍然想在 5 秒后回復)。從現在開始,客戶必須對工作進行輪詢——但沖突是:a) 當 ServeHTTP 退出時 - 然后 ResponseWriter 關閉 - 為了能夠回復客戶端,我們必須將答案寫入 ResponseWriter。b) 如果我阻止 serveHTTP(就像在下面的代碼示例中,我沒有將 func 稱為 go 例程)那么它不僅會影響單個 API 調用,而且似乎會影響之后的所有其他調用,所以第一個呼叫將被及時正確地服務,但是在第一個呼叫之后同時進入的呼叫將被阻塞操作順序延遲。c) 如果我不阻止它 ex - 并將其更改為 go 例程:    gv.jobs <- newPrintJob    go func(doneChan chan struct{},w http.ResponseWriter) {然后沒有延遲 - 可以調用許多 API - 但問題是 serveHTTP 立即存在并因此殺死 ResponseWriter 然后我無法回復客戶端。我不確定如何解決這個沖突,因為我不會對 serveHTTP 造成任何阻塞,所以我可以并行處理所有請求,但仍然能夠回復有問題的 ResponseWriter。有什么方法可以防止 serveHTTP 在函數退出時關閉響應編寫器?
查看完整描述

3 回答

?
UYOU

TA貢獻1878條經驗 獲得超4個贊

是的,如果我不阻止它,你的觀點“c) 是正確的” 。

為了保存響應編寫器,您不應該在其中調用 go routine。相反,您應該將ServeHTTP作為 go-routine 調用,大多數 http 服務器實現都這樣做。
這樣你就不會阻止任何 api 調用,每個 api 調用將在不同的 go-routine 中運行,被它們的功能阻止。

由于您的“jobs chan QueueElement”是單個通道(不是緩沖通道),因此您的所有進程都在“gv.jobs <- newPrintJob”處被阻塞。
您應該使用緩沖通道,以便所有 api 調用都可以將其添加到隊列中并根據工作完成或超時獲得響應。

擁有緩沖通道也可以模擬打印機在現實世界中的內存限制。(隊列長度 1 是特例)


查看完整回答
反對 回復 2023-06-19
?
慕的地6264312

TA貢獻1817條經驗 獲得超6個贊

我已經為您的代碼添加了一些更新?,F在它像你描述的那樣工作。


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

}



查看完整回答
反對 回復 2023-06-19
?
牛魔王的故事

TA貢獻1830條經驗 獲得超3個贊

select語句應該在 goroutine 函數之外并阻止請求直到作業執行結束或達到超時。



查看完整回答
反對 回復 2023-06-19
  • 3 回答
  • 0 關注
  • 166 瀏覽
慕課專欄
更多

添加回答

舉報

0/150
提交
取消
微信客服

購課補貼
聯系客服咨詢優惠詳情

幫助反饋 APP下載

慕課網APP
您的移動學習伙伴

公眾號

掃描二維碼
關注慕課網微信公眾號