首頁 > 後端開發 > Golang > 如何在golang中根據ID取消頻道作業

如何在golang中根據ID取消頻道作業

PHPz
發布: 2024-02-08 23:42:11
轉載
750 人瀏覽過

如何在golang中根據ID取消頻道作業

在golang中,取消頻道作業是常見的需求。當我們在處理並發任務時,有時需要根據任務的ID來取消正在執行的任務。那麼,在golang中如何實作這個功能呢?下面,我將為大家介紹一個簡單有效的方法。首先,我們需要建立一個帶有緩衝的通道,用於儲存任務的ID。然後,我們可以使用select語句來監聽通道的讀取操作,並在需要取消任務時,將任務的ID傳送到通道中。接著,在任務的執行函數中,我們可以透過判斷通道是否已關閉來確定是否需要取消任務。如果通道被關閉,表示任務已被取消,我們可以在適當的地方終止任務的執行。透過這種方式,我們可以方便地在golang中根據ID取消通道作業。以上就是php小編新一為大家介紹的方法,希望對大家有幫助!

問題內容

所以我有一個 post 端點,它會建立一個作業並將它們加入到一個 chan 中。 workerjobschan = make(chan job, maxqueuesize)

這就是我在頻道中執行作業的方式(main.go):

for i := 1; i <= maxworkers; i++ {
    go func(i int) {
        for job := range workerjobschan {
            ctx, cancel := context.withcancel(context.background())
            storejob(job.search.id, cancel)
            job.execute(ctx, c.db, i)
        }
    }(i)
}
登入後複製

我將取消函數儲存在地圖中:canceljobfuncs = make(map[int]context.cancelfunc)

這是工作職能:

func (j *job) execute(ctx context.context, db *sql.db, workerid int) error {


    for {
        select {
        // check for cancellation signal
        case <-ctx.done():
             if err := ctx.err(); err != nil {
                fmt.println("worker", workerid, "error", err)
             }
            fmt.println("worker", workerid, "cancelled")
            return nil

        default:
            fmt.printf("worker%d: processing %s\n", workerid, j.search.query)
            time.sleep(2 * time.second)
            fmt.printf("worker%d: active %s\n", workerid, j.search.query)
            time.sleep(5 * time.second)
            fmt.printf("worker%d: completed %s!\n", workerid, j.search.query)

        }
    }
}
登入後複製

我取消這樣的上下文(在http處理程序中):

cancelJob(search.ID)
登入後複製

但該作業仍在繼續運作。我嘗試了很多東西,但似乎無法讓它發揮作用。

解決方法

這裡有一個方法可以說明一個明顯的觀點:如果您的程式碼不檢查ctx.done(),它就無法知道它已被取消。
(順便說一句,這是@jimb 在對您的問題的評論中所寫內容的另一種改寫)。

因此,當 .execute(...) 方法中的程式碼開始執行此區塊時:

fmt.printf("worker%d: processing %s\n", workerid, j.search.query)
    time.sleep(2 * time.second)
    fmt.printf("worker%d: active %s\n", workerid, j.search.query)
    time.sleep(5 * time.second)
    fmt.printf("worker%d: completed %s!\n", workerid, j.search.query)
登入後複製

它將到達該區塊的末尾(7 秒)。沒有任何指令告訴它在取消時停止。

如果您希望函數能夠在「睡眠」指令期間偵測取消,則必須變更程式碼。

以下是如何使用您的範例執行此操作的一個範例:

func (j *job) execute(ctx context.context, db *sql.db, workerid int) error {


    for {
        fmt.printf("worker%d: processing %s\n", workerid, j.search.query)

        // rewrite time.sleep() with time.after() so that it can be composed
        // in a select statement:
        select {
        case <-ctx.done():
            fmt.println("worker", workerid, "cancelled")
            return nil
        case <-time.after(2 * time.second):
            // keep going
        }

        fmt.printf("worker%d: active %s\n", workerid, j.search.query)

        select {
        case <-ctx.done():
            fmt.println("worker", workerid, "cancelled")
            return nil
        case <-time.after(5 * time.second):
            // keep going
        }

        fmt.printf("worker%d: completed %s!\n", workerid, j.search.query)
    }
}
登入後複製

//m.sbmmt.com/link/3bc31a430954d8326605fc690ed22f4d

我猜你的實際程式碼沒有time.sleep() 指令,而是processsearch(...)doquery(...)或...

如果您需要這些函數在執行期間可取消,則需要以某種方式將取消上下文傳遞給它們,並讓它們以某種方式檢查取消情況。

「傳遞上下文」的一種方法顯然是將其添加到所述函數的參數中:

processsearch(ctx, ...)
doquery(ctx, ...)
登入後複製

但根據您現有的程式碼,某些參數可能已經有內建的方法可以取消。
舉例來說:

// an http.Request carries a context:
func doQuery(req *http.Request, ....) {
    ...
}

// at call site:
    ...
    req := http.NewRequestWithContext(ctx, "GET", "https://some.other.service/", nil)
    doQuery(req, ...)
登入後複製

以上是如何在golang中根據ID取消頻道作業的詳細內容。更多資訊請關注PHP中文網其他相關文章!

來源:stackoverflow.com
本網站聲明
本文內容由網友自願投稿,版權歸原作者所有。本站不承擔相應的法律責任。如發現涉嫌抄襲或侵權的內容,請聯絡admin@php.cn
熱門教學
更多>
最新下載
更多>
網站特效
網站源碼
網站素材
前端模板