在上一次Wait返回之前重新使用WaitGroup

sci*_*igs 6 go

因此,我将进一步使用golang并进一步了解它提供的并发性.我决定尝试使用go例程来实现电话号码中字符串的排列.

我遇到了使用sync.WaitGroup来协调我一直在使用的go例程的问题.具体错误是:

WaitGroup is reused before previous Wait has returned

代码是:

main.go

package main

import (
    "fmt"
    "sync"

    "github.com/sbiscigl/phonenumberperm/intstack"
    "github.com/sbiscigl/phonenumberperm/permutations"
)

var wg sync.WaitGroup

func main() {
    num := []int{2, 7, 1, 4, 5, 5, 2}    
    stack := intstack.New(num)
    permutationChannel := make(chan string)
    wg.Add(1)
    go permutations.ThreadSafeCalcWords(stack, "", permutationChannel, &wg)
    wg.Wait()
    /*Then consume, but not implimented*/
}
Run Code Online (Sandbox Code Playgroud)

排列/ perm.go

package permutations

import (
    "fmt"
    "sync"

    "github.com/sbiscigl/phonenumberperm/intstack"
)

var letterMap = map[int][]string{
    2: []string{"a", "b", "c"},
    3: []string{"d", "e", "f"},
    4: []string{"g", "h", "i"},
    5: []string{"j", "k", "l"},
    6: []string{"m", "n", "o"},
    7: []string{"p", "q", "r", "s"},
    8: []string{"t", "u", "v"},
    9: []string{"w", "x", "y", "z"},
}

func ThreadSafeCalcWords(s intstack.IntStack, word string, ch chan<- string,
    wg *sync.WaitGroup) {
    if s.IsEmpty() {
        ch <- fmt.Sprint(word)
        wg.Done()
    } else {
        /*Check to see if the values are 1 or zero as they*/
        /*have no letters associated with them*/
        if s.Peek() == 1 || s.Peek() == 0 {
            wg.Done()
            s.Pop()
            wg.Add(1)
            go ThreadSafeCalcWords(s, word, ch, wg)
        } else {
            wg.Done()
            for _, letter := range letterMap[s.Pop()] {
                wg.Add(1)
                go ThreadSafeCalcWords(s, word+letter, ch, wg)
            }
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

intstack/intstack.go

package intstack

import "fmt"

const (
    maxSize = 100
)

/*IntStack implimentaiton of a stack for integers*/
type IntStack struct {
    valueList []int
    maxSize   int
}

/*New returns bew instace of IntStack*/
func New(nums []int) IntStack {
    return IntStack{
        valueList: nums,
        maxSize:   maxSize,
    }
}

/*Pop pops the top value off the stack*/
func (s *IntStack) Pop() int {
    var val int
    if !s.IsEmpty() {
        val = s.valueList[0]
        s.valueList = s.valueList[1:]
    } else {
        fmt.Println("stack is empty")
    }
    return val
}

/*Peek returns top value*/
func (s IntStack) Peek() int {
    return s.valueList[0]
}

/*IsEmpty checks if the stack is empty*/
func (s IntStack) IsEmpty() bool {
    if len(s.valueList) > 0 {
        return false
    }
    return true
}

/*Print prints out the contents of the stack*/
func (s IntStack) Print() {
    for _, element := range s.valueList {
        fmt.Print(element)
    }
    fmt.Print("\n")
}
Run Code Online (Sandbox Code Playgroud)

所以经过研究,在wg.Wait()或者等待组等待函数期间调用该行.我尝试用较小的程序复制,但不能.我的假设是,一旦它在调用go例程后到达Wait(),我们就不能再编辑等待组,但这听起来是错误的.任何有关为什么会发生这种情况的见解都会有所帮助

可以在以下网址找到repo for refrence:https://github.com/sbiscigl/phonenumberperm

hob*_*bbs 8

在你的递归案例中ThreadSafeCalcWords,你在打电话wg.Done 之前打电话wg.Add.这意味着Wait在你真正完成所有工作之前,wg可以下降到0(这将触发完成).AddWait仍处于解决过程中再次调用是触发错误的原因,但更重要的是,它可能只是简单而不是你想要的.

更改操作顺序,以便在完成现有工作Add之前始终有任何新Done工作,并且Wait不会过早触发.完成此操作的最简单方法可能是wg.Done()在函数底部单个调用,或defer在顶部单个调用,并删除所有其他函数.