यह @Jimt द्वारा लिखे गए गो में श्रमिकों और नियंत्रक मोड का एक अच्छा उदाहरण है, " क्या गोलंग में किसी अन्य गोरोइन को रोकने और फिर से शुरू करने के लिए कुछ सुरुचिपूर्ण तरीका है? "
package main
import (
"fmt"
"runtime"
"sync"
"time"
)
// Possible worker states.
const (
Stopped = 0
Paused = 1
Running = 2
)
// Maximum number of workers.
const WorkerCount = 1000
func main() {
// Launch workers.
var wg sync.WaitGroup
wg.Add(WorkerCount + 1)
workers := make([]chan int, WorkerCount)
for i := range workers {
workers[i] = make(chan int)
go func(i int) {
worker(i, workers[i])
wg.Done()
}(i)
}
// Launch controller routine.
go func() {
controller(workers)
wg.Done()
}()
// Wait for all goroutines to finish.
wg.Wait()
}
func worker(id int, ws <-chan int) {
state := Paused // Begin in the paused state.
for {
select {
case state = <-ws:
switch state {
case Stopped:
fmt.Printf("Worker %d: Stopped\n", id)
return
case Running:
fmt.Printf("Worker %d: Running\n", id)
case Paused:
fmt.Printf("Worker %d: Paused\n", id)
}
default:
// We use runtime.Gosched() to prevent a deadlock in this case.
// It will not be needed of work is performed here which yields
// to the scheduler.
runtime.Gosched()
if state == Paused {
break
}
// Do actual work here.
}
}
}
// controller handles the current state of all workers. They can be
// instructed to be either running, paused or stopped entirely.
func controller(workers []chan int) {
// Start workers
for i := range workers {
workers[i] <- Running
}
// Pause workers.
<-time.After(1e9)
for i := range workers {
workers[i] <- Paused
}
// Unpause workers.
<-time.After(1e9)
for i := range workers {
workers[i] <- Running
}
// Shutdown workers.
<-time.After(1e9)
for i := range workers {
close(workers[i])
}
}
लेकिन इस कोड में एक मुद्दा भी है: यदि आप बाहर निकलते workers
समय किसी कार्यकर्ता चैनल को हटाना चाहते हैं worker()
, तो डेड लॉक होता है।
यदि आप close(workers[i])
, अगली बार नियंत्रक लिखते हैं, तो इससे घबराहट होगी क्योंकि गो बंद चैनल में नहीं लिख सकता है। यदि आप इसे बचाने के लिए कुछ म्यूटेक्स का उपयोग करते हैं, तो यह पर अटक जाएगाworkers[i] <- Running
क्योंकि worker
चैनल से कुछ भी नहीं पढ़ रहा है और लिखना अवरुद्ध हो जाएगा, और म्यूटेक्स एक मृत लॉक का कारण होगा। आप वर्क-अराउंड के रूप में चैनल को एक बड़ा बफर भी दे सकते हैं, लेकिन यह काफी अच्छा नहीं है।
इसलिए मुझे लगता है कि इसे हल करने का सबसे अच्छा तरीका है worker()
बाहर निकलने के समय नजदीकी चैनल है, अगर नियंत्रक एक चैनल बंद पाता है, तो वह इस पर कूद जाएगा और कुछ भी नहीं करेगा। लेकिन मुझे नहीं पता कि इस स्थिति में किसी चैनल को पहले से ही कैसे बंद किया जाए या नहीं। यदि मैं नियंत्रक में चैनल को पढ़ने की कोशिश करता हूं, तो नियंत्रक अवरुद्ध हो सकता है। इसलिए मैं अभी बहुत उलझन में हूं।
पुनश्च: उठे हुए घबराहट को ठीक करना जो मैंने कोशिश की है, लेकिन यह गोरोइन को बंद कर देगा जिसने घबराहट को बढ़ाया। इस मामले में यह नियंत्रक होगा इसलिए इसका कोई उपयोग नहीं है।
फिर भी, मुझे लगता है कि गो के अगले संस्करण में इस फ़ंक्शन को लागू करने के लिए गो टीम के लिए यह उपयोगी है।