2013-05-16 11 views
7

की समाप्ति की प्रतीक्षा करें मुझे बड़ी मात्रा में goroutines शुरू करने और उनकी समाप्ति की प्रतीक्षा करने की आवश्यकता है। सहज तरीके तक उन सभी को पूरा कर लें प्रतीक्षा करने के लिए एक चैनल का उपयोग करने लगता है:एन goroutines

package main 

type Object struct { 
    //data 
} 

func (obj *Object) Update(channel chan int) { 
    //update data 
    channel <- 1 
    return 
} 

func main() { 

    channel := make(chan int, n) 
    list := make([]Object, n, m) 
    for { 
     for _, object := range list { 
      go object.Update(channel) 
     } 
     for i := 0; i < n; i++ { 
      <-channel 
     } 
     //now everything has been updated. start again 
    } 
} 

लेकिन समस्या यह है कि वस्तुओं की मात्रा और इसलिए goroutines की राशि बदल सकता है। क्या चैनल के बफर आकार को बदलना संभव है?

क्या ऐसा करने के लिए शायद एक और शानदार तरीका है?

+2

आप इसे प्रत्येक यात्रा को पुनः निर्दिष्ट कर सकता है, लेकिन आप [WaitGroup] (http://golang.org/pkg/sync/#WaitGroup) को देखने के लिए चाहते हो सकता है। – tjameson

+0

tjameson, त्वरित मदद के लिए धन्यवाद। यह वास्तव में अच्छा लग रहा है। आप इसे एक उत्तर बनाना चाहते हैं। – lhk

+0

हो गया, उदाहरण के साथ = डी – tjameson

उत्तर

27

मैंने इस समस्या के समाधान के रूप में WaitGroup का उपयोग किया है। अपने वर्तमान कोड का अनुवाद करना, कुछ लॉग के साथ यह स्पष्ट क्या हो रहा है बनाने के लिए:

package main 

import "sync" 
import "fmt" 
import "time" 

type Object struct { 
    //data 
} 

func (obj *Object) Update(wg *sync.WaitGroup) { 
    //update data 
    time.Sleep(time.Second) 
    fmt.Println("Update done") 
    wg.Done() 
    return 
} 

func main() { 
    var wg sync.WaitGroup 
    list := make([]Object, 5) 
    for { 
     for _, object := range list { 
      wg.Add(1) 
      go object.Update(&wg) 
     } 
     //now everything has been updated. start again 
     wg.Wait() 
     fmt.Println("Group done") 
    } 
} 
+8

अच्छा जवाब! मैं शायद 'अपडेट' की शुरुआत में 'defer wg.Done() 'डाल दूंगा, हालांकि भविष्य में कुछ समय में कार्य बढ़ता है और शुरुआती वापसी प्राप्त करता है। –

+0

या यदि कोई आतंक या कुछ है तो। – tjameson

4

यह कार्य बिल्कुल तुच्छ नहीं है, यह एक छोटी गाड़ी लिखना काफी आसान है। मैं stdlib - sync.WaitGroup में तैयार किए गए समाधान का उपयोग करने की अनुशंसा करता हूं। लिंक से उद्धरण:

एक प्रतीक्षा समूह समाप्त करने के लिए goroutines के संग्रह की प्रतीक्षा करता है। मुख्य goroutine कॉल इंतजार करने के लिए goroutines की संख्या निर्धारित करने के लिए जोड़ें। फिर प्रत्येक goroutines चलाता है और समाप्त होने पर पूर्ण हो जाता है। उसी समय, प्रतीक्षा करें जब तक कि सभी goroutines समाप्त नहीं हो जाता है।

+0

और अगर गोरोटाइन की प्रतीक्षा करने की संख्या अग्रिम में ज्ञात नहीं है? – Dfr

+0

@ डीआरएफ जब आप प्रत्येक गोराउटिन शुरू करते हैं तो काउंटर में वृद्धि होती है, इसलिए यह समाधान तब भी सबसे अच्छा समाधान है जब आप goroutines की संख्या को नहीं जानते हैं। – Awn

0

@tjameson एक महान काम WaitGroup, कैसे अपने कार्य करने के लिए अपने WaitGroup ऑब्जेक्ट के संदर्भ पारित करने के लिए उपयोग करने के लिए कैसे समझा था। जब आप Done होते हैं तो एक बदलाव जो मैं उनके उदाहरण में करता हूं वह defer का लाभ उठाता है। मुझे लगता है कि यह defer ws.Done() आपके फ़ंक्शन में पहला कथन होना चाहिए।

मुझे WaitGroup की सादगी पसंद है। हालांकि, मुझे यह पसंद नहीं है कि हमें goroutine के संदर्भ को पारित करने की आवश्यकता है क्योंकि इसका मतलब यह होगा कि समेकन तर्क आपके व्यापार तर्क के साथ मिश्रित किया जाएगा।

तो मैं मेरे लिए इस समस्या को हल करने के लिए इस सामान्य समारोह के साथ आया था:

// Parallelize parallelizes the function calls 
func Parallelize(functions ...func()) { 
    var waitGroup sync.WaitGroup 
    waitGroup.Add(len(functions)) 

    defer waitGroup.Wait() 

    for _, function := range functions { 
     go func(copy func()) { 
      defer waitGroup.Done() 
      copy() 
     }(function) 
    } 
} 

तो अपने उदाहरण इस तरह से हल किया जा सकता:

type Object struct { 
    //data 
} 

func (obj *Object) Update() { 
    //update data 
    time.Sleep(time.Second) 
    fmt.Println("Update done") 
    return 
} 

func main() { 
    functions := []func(){} 
    list := make([]Object, 5) 
    for _, object := range list { 
     function := func(obj Object){ object.Update() }(object) 
     functions = append(functions, function) 
    } 

    Parallelize(functions...)   

    fmt.Println("Group done") 
} 

आप इसका इस्तेमाल करना चाहते हैं तो, आप इसे पा सकते हैं यहाँ https://github.com/shomali11/util

संबंधित मुद्दे