2016-05-28 4 views
0

スレッド安全性の面でティッカーを作成する場所はどこですか?

ticker := time.NewTicker(1 * time.Second) 

go func() { 
    for _ = range ticker.C { 
     fmt.Print("Tick") 
    } 
}() 

time.Sleep(3) 
ticker.Stop() 

var ticker *time.Ticker 

go func() { 
    ticker = time.NewTicker(1 * time.Second) 
    for _ = range ticker.C { 
     fmt.Print("Tick") 
    } 
}() 

time.Sleep(3) 
ticker.Stop() 

の間に違いは、関数内の仕事はダニの期間よりも長くかかる場合は特に、ありますか? (必要とされていないティッカーを停止する場合)前者はできませんが、後者は

go func() { 
    for ticker := time.NewTicker(1 * time.Second) ;; <-ticker.C { 
     fmt.Print("Tick") 
    } 
}() 

に短縮することができますので、私は求めています

。このフォームには、最初のティックがすぐにトリガーされるという追加の利点があります。

+0

実際には違いはありません。しかし、ゴルーチンへのパラメータとして、囲みスコープから必要な変数を渡すことをお勧めします。 –

答えて

2

コードの2番目のバージョンは間違っています。競合状態です。

var ticker *time.Ticker 

go func() { 
    ticker = time.NewTicker(1 * time.Second) 
    for _ = range ticker.C { 
     fmt.Print("Tick") 
    } 
}() 

time.Sleep(3) 
ticker.Stop() 

ゴルーチン内部tickerへの割り当てとticker.Stop()コールでtickerの使用の間には同期はありません。

実際にはこれは長いtime.Sleep(3)のためにほとんど無害ですが、今日は無害であっても後でトラブルを引き起こす可能性があるため、この種のレースは避けるべきです。たとえば、Sleepの代わりに、可変長のコードがある場合、そのコードの実行に非常に短い時間がかかると、ポインタのパニックが発生することがあります。

そのため、私はいつもあなたのコードの最初のバージョン(ゴルーチン外にtickerを作成するコード)を使用します。

コードの第3のバージョン(tickerが完全にゴルーチン内で使用されている)も良いです。可能であれば、私はこの短いバージョンのコードをgoroutineの内部でティッカーが定義されているところで使っています。コードの短さはいいですが、私はまた、コードの外側にはティッカーが全く見えないので、コードの読者がティッカーの範囲を理解するのは簡単です。

+0

あなたは「第3のバージョンも良いです」と言っています。これは、たとえそれが仕事をしている同じGoroutineに定義されていても、Tickerが適切に動作することを意味します。 – AndreKR

+0

@AndreKRはい、定義されている同じゴルーチンの変数を使用するのは正常です。すべてのプログラムには、メインでコードを実行するゴルーチンが少なくとも1つはあることを理解するのに役立ちます。 –

+0

私は多分ゴルーチンが忙しかったと思ったかもしれませんが、ティッカーはチャンネルに次のティックを送るチャンスを得られませんでしたが、実際に意味をなさない第2の考えでは、ティッカーはどんな場合でも別の内部ゴルーチンを必要とします。 – AndreKR

関連する問題