गोरोचन कैसे रोकें


102

मेरे पास एक गोरोइन है जो एक विधि को कॉल करता है, और एक चैनल पर लौटाया गया मान देता है:

ch := make(chan int, 100)
go func(){
    for {
        ch <- do_stuff()
    }
}()

मैं ऐसे गोरोचन को कैसे रोकूं?


1
एक अन्य उत्तर, आपकी स्थिति पर निर्भर करता है, एक गो संदर्भ का उपयोग करना है। मेरे पास इस बारे में जवाब बनाने के लिए समय या ज्ञान नहीं है। मैं सिर्फ यहाँ इसका उल्लेख करना चाहता था ताकि खोज करने वाले और असंतोषजनक इस उत्तर को खोजने वाले लोगों के पास खींचने के लिए एक और धागा हो। ज्यादातर मामलों में, आपको स्वीकार किए गए उत्तर का सुझाव देना चाहिए। इस उत्तर में संदर्भों का उल्लेख है: stackoverflow.com/a/47302930/167958
सर्वव्यापी

जवाबों:


50

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

15
आंतरिक गोरोइन का शरीर अधिक मुहावरेदार रूप deferसे कॉल का उपयोग करके लिखा गया है wg.Done(), और range chचैनल बंद होने तक सभी मूल्यों पर पुनरावृति करने के लिए एक लूप है।
एलन डोनोवन

115

आमतौर पर, आप गोरआउट एक (संभवतः अलग) सिग्नल चैनल पास करते हैं। उस सिग्नल चैनल का उपयोग किसी मान को पुश करने के लिए किया जाता है जब आप चाहते हैं कि गोरोइन बंद हो जाए। गोरोत्रिन नियमित रूप से उस चैनल का चुनाव करती है। जैसे ही यह एक संकेत का पता लगाता है, यह समाप्त हो जाता है।

quit := make(chan bool)
go func() {
    for {
        select {
        case <- quit:
            return
        default:
            // Do other stuff
        }
    }
}()

// Do stuff

// Quit goroutine
quit <- true

26
बहुत अच्छा नहीं। यदि बग के कारण गोरोइन अंतहीन लूप में फंस गया है, तो क्या होगा?
एलज़ार लीबोविच

232
फिर बग को ठीक किया जाना चाहिए।
jimt

13
एलज़र, आप जो सुझाव देते हैं वह आपके द्वारा कॉल करने के बाद किसी फ़ंक्शन को रोकने का एक तरीका है। गोरोइन एक धागा नहीं है। यह एक अलग धागे में चल सकता है या यह आपके समान धागे में चल सकता है। मुझे कोई भी भाषा नहीं पता है जो आपको लगता है कि गो का समर्थन करना चाहिए जो समर्थन करता है।
जेरेमी वॉल

5
@ जेरेमी गो के लिए असहमत नहीं है, लेकिन एरलैंग आपको एक प्रक्रिया को मारने की अनुमति देता है जो एक लूपिंग फ़ंक्शन चला रहा है।
मैथ्यूटोडे

10
जाओ मल्टीटास्किंग सहकारी है, प्रीमेप्टिव नहीं। लूप में एक गोरोइनिन कभी भी अनुसूचक में प्रवेश नहीं करता है, इसलिए इसे कभी भी नहीं मारा जा सकता है।
जेफ एलन

34

आप बाहर से गोरोइन को नहीं मार सकते। आप किसी चैनल का उपयोग बंद करने के लिए एक गोरोइन का संकेत दे सकते हैं, लेकिन किसी भी प्रकार के मेटा प्रबंधन को करने के लिए गोरोइंटिन पर कोई हैंडल नहीं है। गोराउटाइन का उद्देश्य सहकारी रूप से समस्याओं को हल करना है, इसलिए दुर्व्यवहार करने वाले को मारना लगभग कभी पर्याप्त प्रतिक्रिया नहीं होगी। यदि आप मजबूती के लिए अलगाव चाहते हैं, तो आप शायद एक प्रक्रिया चाहते हैं।


और आप एन्कोडिंग / gob पैकेज में देखना चाहते हैं, जो दो गो कार्यक्रमों को आसानी से एक पाइप पर डेटा संरचनाओं का आदान-प्रदान कर सकता है।
जेफ एलन

मेरे मामले में, मेरे पास एक गोरोइन है जो एक सिस्टम कॉल पर अवरुद्ध हो जाएगा, और मुझे इसे सिस्टम कॉल को निरस्त करने और फिर बाहर निकलने के लिए बताने की आवश्यकता है। यदि मुझे पढ़ा गया चैनल पर ब्लॉक किया गया है, तो जैसा कि आप सुझाव देते हैं, ऐसा करना संभव होगा।
सर्वव्यापी

मैंने उस मुद्दे को पहले देखा था। जिस तरह से हमने "हल किया" यह था कि आवेदन की शुरुआत में थ्रेड्स की संख्या में वृद्धि करने के लिए गोरोइटिन की संख्या से मेल खाएं जो संभवतः सीपीयू की संख्या +
रौज़ियर

18

आम तौर पर, आप एक चैनल बना सकते हैं और गोरआउट में स्टॉप सिग्नल प्राप्त कर सकते हैं।

इस उदाहरण में चैनल बनाने के दो तरीके हैं।

  1. चैनल

  2. संदर्भ । उदाहरण में मैं डेमो करूंगा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")
}

11

मुझे पता है कि यह उत्तर पहले ही स्वीकार कर लिया गया है, लेकिन मुझे लगा कि मैं अपने 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()...
ग्वेनेथ लेलेवेन

1
हाय ग्वेनेथ, हाँ proc.Tomb.Done()इससे पहले कि यह कार्यक्रम दुर्घटनाग्रस्त हो जाए, लेकिन क्या अंत होगा? यह संभव है कि मुख्य गोरोइनट के पास कुछ बयानों को निष्पादित करने के लिए अवसर की एक बहुत छोटी खिड़की हो सकती है , लेकिन इसके पास एक अन्य गोरआउट में आतंक से उबरने का कोई रास्ता नहीं है, इसलिए कार्यक्रम अभी भी दुर्घटनाग्रस्त हो जाता है। डॉक्स कहते हैं: "जब फ़ंक्शन एफ घबराता है, तो एफ का निष्पादन बंद हो जाता है, एफ में किसी भी स्थगित कार्य को सामान्य रूप से निष्पादित किया जाता है, और फिर एफ अपने कॉलर पर वापस आ जाता है..यह प्रक्रिया तब तक जारी रहती है जब तक कि वर्तमान गोरोइन में सभी फ़ंक्शन वापस नहीं आ जाते हैं, जिस पर प्रोग्राम क्रैश हो जाता है। "
केविन कैंटवेल

7

व्यक्तिगत रूप से, मैं एक चैनल पर एक goroutine में श्रेणी का उपयोग करना चाहूंगा:

https://play.golang.org/p/qt48vvDu8cd

डेव ने इसके बारे में एक शानदार पोस्ट लिखा है: http://dave.cheney.net/2013/04/30/curious-channels


1
यह वास्तव में सुंदर है।
प्रोफैट्सच
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.