मेरे पास एक गोरोइन है जो एक विधि को कॉल करता है, और एक चैनल पर लौटाया गया मान देता है:
ch := make(chan int, 100)
go func(){
for {
ch <- do_stuff()
}
}()
मैं ऐसे गोरोचन को कैसे रोकूं?
मेरे पास एक गोरोइन है जो एक विधि को कॉल करता है, और एक चैनल पर लौटाया गया मान देता है:
ch := make(chan int, 100)
go func(){
for {
ch <- do_stuff()
}
}()
मैं ऐसे गोरोचन को कैसे रोकूं?
जवाबों:
EDIT: मैंने यह जवाब जल्दबाजी में लिखा है, यह महसूस करने से पहले कि आपका सवाल गोरोइन के अंदर एक चान को मान भेजने के बारे में है। नीचे दिए गए दृष्टिकोण का उपयोग या तो एक अतिरिक्त चान के साथ किया जा सकता है जैसा कि ऊपर बताया गया है, या इस तथ्य का उपयोग करके कि आपके पास पहले से ही जो चान है वह द्वि-दिशात्मक है, आप बस एक का उपयोग कर सकते हैं ...
यदि आपका गोरोइन केवल चान से निकलने वाली वस्तुओं को संसाधित करने के लिए मौजूद है, तो आप "करीब" बिलिन और चैनलों के लिए विशेष प्राप्त फ़ॉर्म का उपयोग कर सकते हैं।
यही है, एक बार जब आप चान पर आइटम भेज रहे हैं, तो आप इसे बंद कर देते हैं। फिर अपने गोरोइन के अंदर आपको प्राप्त ऑपरेटर को एक अतिरिक्त पैरामीटर मिलता है जो दिखाता है कि चैनल बंद हो गया है या नहीं।
यहाँ एक पूर्ण उदाहरण है (यह सुनिश्चित करने के लिए कि यह प्रक्रिया जारी है जब तक कि गोरोइन पूरा नहीं हो जाता है, वेटग्रुप का उपयोग किया जाता है:
package main
import "sync"
func main() {
var wg sync.WaitGroup
wg.Add(1)
ch := make(chan int)
go func() {
for {
foo, ok := <- ch
if !ok {
println("done")
wg.Done()
return
}
println(foo)
}
}()
ch <- 1
ch <- 2
ch <- 3
close(ch)
wg.Wait()
}
defer
से कॉल का उपयोग करके लिखा गया है wg.Done()
, और range ch
चैनल बंद होने तक सभी मूल्यों पर पुनरावृति करने के लिए एक लूप है।
आमतौर पर, आप गोरआउट एक (संभवतः अलग) सिग्नल चैनल पास करते हैं। उस सिग्नल चैनल का उपयोग किसी मान को पुश करने के लिए किया जाता है जब आप चाहते हैं कि गोरोइन बंद हो जाए। गोरोत्रिन नियमित रूप से उस चैनल का चुनाव करती है। जैसे ही यह एक संकेत का पता लगाता है, यह समाप्त हो जाता है।
quit := make(chan bool)
go func() {
for {
select {
case <- quit:
return
default:
// Do other stuff
}
}
}()
// Do stuff
// Quit goroutine
quit <- true
आप बाहर से गोरोइन को नहीं मार सकते। आप किसी चैनल का उपयोग बंद करने के लिए एक गोरोइन का संकेत दे सकते हैं, लेकिन किसी भी प्रकार के मेटा प्रबंधन को करने के लिए गोरोइंटिन पर कोई हैंडल नहीं है। गोराउटाइन का उद्देश्य सहकारी रूप से समस्याओं को हल करना है, इसलिए दुर्व्यवहार करने वाले को मारना लगभग कभी पर्याप्त प्रतिक्रिया नहीं होगी। यदि आप मजबूती के लिए अलगाव चाहते हैं, तो आप शायद एक प्रक्रिया चाहते हैं।
आम तौर पर, आप एक चैनल बना सकते हैं और गोरआउट में स्टॉप सिग्नल प्राप्त कर सकते हैं।
इस उदाहरण में चैनल बनाने के दो तरीके हैं।
चैनल
संदर्भ । उदाहरण में मैं डेमो करूंगाcontext.WithCancel
पहला डेमो, उपयोग channel
:
package main
import "fmt"
import "time"
func do_stuff() int {
return 1
}
func main() {
ch := make(chan int, 100)
done := make(chan struct{})
go func() {
for {
select {
case ch <- do_stuff():
case <-done:
close(ch)
return
}
time.Sleep(100 * time.Millisecond)
}
}()
go func() {
time.Sleep(3 * time.Second)
done <- struct{}{}
}()
for i := range ch {
fmt.Println("receive value: ", i)
}
fmt.Println("finish")
}
दूसरा डेमो, उपयोग context
:
package main
import (
"context"
"fmt"
"time"
)
func main() {
forever := make(chan struct{})
ctx, cancel := context.WithCancel(context.Background())
go func(ctx context.Context) {
for {
select {
case <-ctx.Done(): // if cancel() execute
forever <- struct{}{}
return
default:
fmt.Println("for loop")
}
time.Sleep(500 * time.Millisecond)
}
}(ctx)
go func() {
time.Sleep(3 * time.Second)
cancel()
}()
<-forever
fmt.Println("finish")
}
मुझे पता है कि यह उत्तर पहले ही स्वीकार कर लिया गया है, लेकिन मुझे लगा कि मैं अपने 2 सेंट को फेंक दूंगा। मुझे कब्र पैकेज का उपयोग करना पसंद है । यह मूल रूप से एक चैनल छोड़ने का काम है, लेकिन यह अच्छी चीजों को भी करता है जैसे कि किसी भी तरह की त्रुटियां। नियंत्रण में दिनचर्या में अभी भी रिमोट किल सिग्नल की जाँच की जिम्मेदारी है। Afaik एक गोरोइन की "आईडी" प्राप्त करना संभव नहीं है और अगर यह दुर्व्यवहार है (यानी: एक अनंत लूप में फंस गया है) तो इसे मार दें।
यहाँ एक सरल उदाहरण है जो मैंने परीक्षण किया है:
package main
import (
"launchpad.net/tomb"
"time"
"fmt"
)
type Proc struct {
Tomb tomb.Tomb
}
func (proc *Proc) Exec() {
defer proc.Tomb.Done() // Must call only once
for {
select {
case <-proc.Tomb.Dying():
return
default:
time.Sleep(300 * time.Millisecond)
fmt.Println("Loop the loop")
}
}
}
func main() {
proc := &Proc{}
go proc.Exec()
time.Sleep(1 * time.Second)
proc.Tomb.Kill(fmt.Errorf("Death from above"))
err := proc.Tomb.Wait() // Will return the error that killed the proc
fmt.Println(err)
}
आउटपुट जैसा दिखना चाहिए:
# Loop the loop
# Loop the loop
# Loop the loop
# Loop the loop
# Death from above
tomb
कि उदाहरण के लिए, घबराहट फेंकने वाले मामले में गोरोइन के साथ क्या होता है? तकनीकी रूप से कहे तो, गोरोइन इस मामले में बाहर निकलता है, इसलिए मैं मान रहा हूं कि यह अभी भी स्थगित कहेगा proc.Tomb.Done()
...
proc.Tomb.Done()
इससे पहले कि यह कार्यक्रम दुर्घटनाग्रस्त हो जाए, लेकिन क्या अंत होगा? यह संभव है कि मुख्य गोरोइनट के पास कुछ बयानों को निष्पादित करने के लिए अवसर की एक बहुत छोटी खिड़की हो सकती है , लेकिन इसके पास एक अन्य गोरआउट में आतंक से उबरने का कोई रास्ता नहीं है, इसलिए कार्यक्रम अभी भी दुर्घटनाग्रस्त हो जाता है। डॉक्स कहते हैं: "जब फ़ंक्शन एफ घबराता है, तो एफ का निष्पादन बंद हो जाता है, एफ में किसी भी स्थगित कार्य को सामान्य रूप से निष्पादित किया जाता है, और फिर एफ अपने कॉलर पर वापस आ जाता है..यह प्रक्रिया तब तक जारी रहती है जब तक कि वर्तमान गोरोइन में सभी फ़ंक्शन वापस नहीं आ जाते हैं, जिस पर प्रोग्राम क्रैश हो जाता है। "
व्यक्तिगत रूप से, मैं एक चैनल पर एक goroutine में श्रेणी का उपयोग करना चाहूंगा:
https://play.golang.org/p/qt48vvDu8cd
डेव ने इसके बारे में एक शानदार पोस्ट लिखा है: http://dave.cheney.net/2013/04/30/curious-channels ।