過去数日間、コマンドラインユーティリティの1つをリファクタリングして、Golangの同時実行性を試してみましたが、行き詰まりました。
ここに 元のコード(マスターブランチ)。
ここに 並行性のあるブランチ(x_concurrentブランチ)。
_go run jira_open_comment_emailer.go
_を使用して並行コードを実行すると、JIRAの問題がチャネルに追加された場合にdefer wg.Done()
が実行されません ここ 、これによりwg.Wait()
が永遠にハングアップします。
JIRAの問題がたくさんあるので、それぞれのゴルーチンをスピンオフして、応答する必要のあるコメントがあるかどうかを確認したいと考えています。もしそうなら、私はそれをいくつかの構造に追加したいと思います(私はいくつかの調査の後にチャネルを選択しました)、後でキューのように読み取って電子メールのリマインダーを作成できます。
コードの関連セクションは次のとおりです。
_// Given an issue, determine if it has an open comment
// Returns true if there is an open comment on the issue, otherwise false
func getAndProcessComments(issue Issue, channel chan<- Issue, wg *sync.WaitGroup) {
// Decrement the wait counter when the function returns
defer wg.Done()
needsReply := false
// Loop over the comments in the issue
for _, comment := range issue.Fields.Comment.Comments {
commentMatched, err := regexp.MatchString("~"+config.JIRAUsername, comment.Body)
checkError("Failed to regex match against comment body", err)
if commentMatched {
needsReply = true
}
if comment.Author.Name == config.JIRAUsername {
needsReply = false
}
}
// Only add the issue to the channel if it needs a reply
if needsReply == true {
// This never allows the defered wg.Done() to execute?
channel <- issue
}
}
func main() {
start := time.Now()
// This retrieves all issues in a search from JIRA
allIssues := getFullIssueList()
// Initialize a wait group
var wg sync.WaitGroup
// Set the number of waits to the number of issues to process
wg.Add(len(allIssues))
// Create a channel to store issues that need a reply
channel := make(chan Issue)
for _, issue := range allIssues {
go getAndProcessComments(issue, channel, &wg)
}
// Block until all of my goroutines have processed their issues.
wg.Wait()
// Only send an email if the channel has one or more issues
if len(channel) > 0 {
sendEmail(channel)
}
fmt.Printf("Script ran in %s", time.Since(start))
}
_
Goroutinesは、バッファリングされていないチャネルへの送信をブロックします。最小限の変更で、ゴルーチンのブロックが解除されます。これは、すべての問題に対応できる容量のあるバッファー付きチャネルを作成することです。
channel := make(chan Issue, len(allIssues))
wg.Wait()を呼び出した後、チャネルを閉じます。