🎄teratailクリスマスプレゼントキャンペーン2024🎄』開催中!

\teratail特別グッズやAmazonギフトカード最大2,000円分が当たる!/

詳細はこちら
Go

Go(golang)は、Googleで開発されたオープンソースのプログラミング言語です。

Q&A

解決済

1回答

393閲覧

Go goroutinで取得した値を配列にしたい

pokerStars

総合スコア67

Go

Go(golang)は、Googleで開発されたオープンソースのプログラミング言語です。

0グッド

0クリップ

投稿2021/01/13 14:07

編集2021/01/15 14:42

go

1package controller 2 3import ( 4 "github.com/gin-gonic/gin" 5 "github.com/sclevine/agouti" 6 "log" 7 "sync" 8) 9 10func chrome() *agouti.Page { 11 agoutiDriver := agouti.ChromeDriver( 12 agouti.ChromeOptions("args", []string{ 13 "--headless", // headlessモードの指定 サイト読み込み時の起動をなくす 14 }), 15 ) 16 agoutiDriver.Start() 17 // defer agoutiDriver.Stop() 18 page, _ := agoutiDriver.NewPage() 19 return page 20} 21 22func DisplayAction(c *gin.Context) { 23 24 wg := &sync.WaitGroup{} 25 26 messages := make([]string, 0, 6) 27 28 test := make(chan []string) 29 30 wg.Add(2) 31 32 go func(){ 33 page := chrome() 34 35 // アイウエオ店 36 page.Navigate("https://www.アイウエオ.co.jp/") 37 title1, _ := page.Title()//アイウエオ 38 39 y := make([]string, 0, len(messages)+2) 40 y = append(y, messages...) 41 y = append(y, title1) 42 43 test <- y 44 45 wg.Done() 46 }() 47 48 go func() { 49 page := chrome() 50 51 // かきくけこ店 52 page.Navigate("https://www.かきくけこ.co.jp/") 53 54 title2, _ := page.Title()//かきくけこ 55 56 a := make([]string, 0, len(messages)+2) 57 a = append(a, messages...) 58 a = append(a, title2) 59 60 test <- a 61 62 wg.Done() 63 }() 64 65 wg.Wait()//これを入れるとここで止まってしまう 66 67 msgs := <-test 68 69 c.HTML(200, "hoge.html", gin.H{ 70 "titles": msgs, 71 72 }) 73}

html

1hoge.html 2 3<!DOCTYPE html> 4<html lang="ja"> 5 <head> 6 <meta charset="UTF-8" /> 7 </head> 8 <body> 9 <ul> 10 <!-- {{define "index"}} --> 11 <br> 12 <h1>{{range .titles}}</h1> 13 <p>{{.}}</p> 14 {{end}} 15 <!-- {{end}} --> 16 </ul> 17 </body> 18</html>

期待する結果
msgs = [{アイウエオ} {かきくけこ}]

参考にした記事

現在配列に値を入れようとしてもtitle1またはtitle2のどちらか片方のみmsgsに値が入ってしまいます。 (例)msgs = [アイウエオ]
そこで&sync.WaitGroup{}を使ってgoroutinの処理が終わってから次の処理にいくことで問題を解決できるのではないかと考えたのですが、
wg.Wait()を入れると止まってしまいます。(ずっとロード中)
&sync.WaitGroup{}の使い方でどこかおかしな点はございますでしょうか?

もしくは他にgoroutinで取得したそれぞれの値(title1,title2)をうまく配列にする方法はございますでしょうか?
お力をお借りしたいです。何卒よろしくお願い致します。

気になる質問をクリップする

クリップした質問は、後からいつでもMYページで確認できます。

またクリップした質問に回答があった際、通知やメールを受け取ることができます。

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

guest

回答1

0

ベストアンサー

WaitGroupとtestチャネルがどちらも待ち受けしていてチャネルの動作条件が満たされません。
チャネルはバッファ無しの場合、送信待ちと受信待ちが双方スタンバイになるまでブロックします。

解決方法のひとつはtestチャネルをバッファ付きでサイズを2以上にすることです。
(結果の受け取りは1度ではなく2度にする必要はあります。)

余談ですが、明確な理由なくスライスのキャパシティを指定するのはやめましょう。
(多くのケースで自動拡張に任せるほうが良いことが多いと思います)

追記

UMLのアクティビティ図でいうところの
フォークに相当するのが「go」キーワード、
ジョインに相当するのは「chan」か「sync.WaitGroup」が使えます。
ジョインの目的のために両方を使う必要はありません。

Gopherの書き方

以下の様にすると目的をはたしつつ、WaitGroupも不要です。
(この書き方がgoroutineから戻り値のある場合のジョインの仕方です。)

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

go

1package main 2 3import "fmt" 4 5func main() { 6 7 messages := []string{} 8 test := make(chan []string) 9 10 go func() { 11 // アイウエオ店 12 // page := chrome() 13 // page.Navigate("https://www.アイウエオ.co.jp/") 14 title1 := "アイウエオ" 15 16 y := []string{} 17 // ... 18 y = append(y, title1) 19 20 test <- y 21 }() 22 23 go func() { 24 // かきくけこ店 25 // page := chrome() 26 // page.Navigate("https://www.かきくけこ.co.jp/") 27 28 title2 := "かきくけこ" 29 30 a := []string{} 31 // ... 32 a = append(a, title2) 33 34 test <- a 35 }() 36 37 messages = append(messages, <-test...) 38 messages = append(messages, <-test...) 39 fmt.Println("titles:", messages) 40}

投稿2021/01/13 21:51

編集2021/01/17 21:09
nobonobo

総合スコア3367

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

nobonobo

2021/01/13 21:54

つまり、現状のコードではwg.Done()が呼ばれる事はありません。
pokerStars

2021/01/16 03:58 編集

返信遅くなりすみません。 バッファ付きでサイズを2以上にすることでwg.Wait()で止まってしまう問題を解決できました。 sync.WaitGroup問題が解決し一歩進めましたのでベストアンサーにさせていただきます! しかし、変わらず配列に2つの値を入れることができていないためジョイン含め見直しています... ご教授ありがとうございました!誠に感謝致します!
nobonobo

2021/01/16 13:24

配列にapendするロジックがないです。testから2度受け取った配列をくっつけてください。
pokerStars

2021/01/19 07:16

コメントありがとうございます! append(messages, <-test...)この書き方で、次の処理に行かずにブロックしながら配列の追加が行えるのですね! とても勉強になりました!! chanelはgoroutine間のデータを送受信するもの。 WaitGroupは「goroutineが処理を終えるまで待ってくれる機能」。 という認識止まりだったのですが、<- chanelで何か値が入るまで次の処理に行かずにブロックさせることができるんですね! sync.Mutexなどと組み合わせる以外ではchanelで書いた方が見やすくなりそうですね!
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

15分調べてもわからないことは
teratailで質問しよう!

ただいまの回答率
85.36%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問