私はGolangの同時実行で、数日間にわたって私のコマンドラインユーティリティの1つをリファクタリングすることによってスイングを試みてきましたが、私は立ち往生しています。なぜ私のGolangチャンネル書き込み禁止永遠にですか?
Here's元のコード(マスターブランチ)。
Here's並行性のあるブランチ(x_concurrentブランチ)。
私はgo run jira_open_comment_emailer.go
と並行コードを実行するとJIRAの問題は私のwg.Wait()
は永遠にハングアップしたチャネルhereに追加された場合、defer wg.Done()
が実行されることはありません。
私は大量の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))
}
あなたは 'len(channel)'を全面に持っていますが、そのチャンネルはバッファされていないので長さはありません。送信を完了するためにはチャンネルから受信する必要があります(一般に、バッファリングされたチャンネルの長さに基づいて決定するのは間違いです。同時操作でその値を変更することができます) – JimB
チャンネルへの私の書き込みの、彼らが完了するのを待って、そしてチャンネルから読む...それはsendが実際に完了せず、 'defer wg.Done()'をトリガーするので決して起こり得ないでしょうか?この並行性の実装には、どのように取り組んでいますか? また、 'cap(channel)'のような容量ではなく、チャンネルの現在の要素数を返すというgieceの状態なので、あなたは 'len(channel)'で正しいとは確信していません。 。 https://golang.org/pkg/builtin/#len –
'len(channel)'はバッファされたチャンネルの現在の項目数を返しますが、チャンネルは通常並行して使用されるので、 'len'あなたがそれを読むとすぐに「古く」なります。一般的に、チャネルからの同時のゴルーチンの送受信があります。 Tour Of Goの[Concurrency](https://tour.golang.org/concurrency/1)セクションをもう一度お読みになり、チャンネルの仕組みをよりよく把握することをお勧めします。 – JimB