Di golang, membatalkan kerja saluran adalah keperluan biasa. Apabila kita berurusan dengan tugasan serentak, kadangkala kita perlu membatalkan tugas pelaksanaan berdasarkan ID tugas. Jadi, bagaimana untuk melaksanakan fungsi ini dalam golang? Di bawah, saya akan memperkenalkan anda kepada kaedah yang mudah dan berkesan. Pertama, kita perlu mencipta saluran penimbal untuk menyimpan ID tugasan. Kami kemudiannya boleh menggunakan pernyataan pilih untuk mendengar operasi bacaan saluran dan menghantar ID tugasan ke saluran apabila tugasan perlu dibatalkan. Kemudian, dalam fungsi pelaksanaan tugas, kita boleh menentukan sama ada tugas itu perlu dibatalkan dengan menilai sama ada saluran ditutup. Jika saluran ditutup, tugas itu telah dibatalkan dan kami boleh menamatkan pelaksanaan tugas di tempat yang sesuai. Dengan cara ini, kami boleh membatalkan kerja saluran dengan mudah berdasarkan ID dalam golang. Di atas adalah kaedah yang diperkenalkan oleh editor php Xinyi, saya harap ia akan membantu semua orang!
Jadi saya ada satu post
端点,它创建一个作业并将它们添加到一个 chan 中。 workerjobschan = make(chan job, maxqueuesize)
Beginilah saya melakukan tugas saya di saluran (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) }
Saya menyimpan fungsi pembatalan dalam peta: canceljobfuncs = make(map[int]context.cancelfunc)
.
Ini adalah fungsi kerja:
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) } } }
Saya membatalkan konteks (dalam pengendali http) seperti ini:
cancelJob(search.ID)
Tetapi kerja tetap berjalan. Saya telah mencuba banyak perkara tetapi nampaknya tidak berjaya.
Berikut ialah cara untuk menggambarkan perkara yang jelas: jika kod anda tidak menyemak ctx.done()
, ia tidak mempunyai cara untuk mengetahui bahawa ia telah dibatalkan.
(BTW, ini adalah satu lagi parafrasa tentang apa yang @jimb tulis dalam ulasan untuk soalan anda).
Jadi apabila kod dalam kaedah .execute(...)
mula melaksanakan blok ini:
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)
Ia akan sampai ke penghujung blok (7 saat). Tiada arahan yang menyuruhnya berhenti pada pembatalan.
Jika anda mahu fungsi anda dapat mengesan pembatalan semasa arahan "tidur", anda perlu menukar kod anda.
Berikut ialah contoh cara melakukan ini menggunakan contoh anda:
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
Saya rasa kod sebenar anda tidak mempunyai time.sleep()
指令,而是 processsearch(...)
或 doquery(...)
atau ...
Jika anda memerlukan fungsi ini boleh dibatalkan semasa pelaksanaan, anda perlu menyerahkan konteks pembatalan kepada mereka entah bagaimana dan minta mereka menyemak pembatalan dalam beberapa cara.
Salah satu cara untuk "lulus konteks" jelas sekali dengan menambahkannya pada parameter fungsi tersebut:
processsearch(ctx, ...) doquery(ctx, ...)
Tetapi bergantung pada kod sedia ada anda, sesetengah parameter mungkin sudah mempunyai kaedah terbina dalam untuk membatalkan.
Contohnya:
// 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, ...)
Atas ialah kandungan terperinci Cara membatalkan kerja saluran berdasarkan ID dalam golang. Untuk maklumat lanjut, sila ikut artikel berkaitan lain di laman web China PHP!