2012-09-04 5 views
7

私は、プッシュおよびポップ機能を持つキュー構造体を作成しようとしています。golangのゴルーチンを使用するときにカウンタを実装する方法は?

私は以下のコードのように、10スレッドのプッシュと10スレッドのポップスのデータを使用する必要があります。

質問: 1.私はプッシュ/ポップした量を印刷する必要がありますが、その方法はわかりません。 2.コードを高速化するにはどうすればよいですか?コードは私にとっては遅すぎます。

package main 

import (
    "runtime" 
    "time" 
) 

const (
    DATA_SIZE_PER_THREAD = 10000000 
) 

type Queue struct { 
    records string 
} 


func (self Queue) push(record chan interface{}) { 
    // need push counter 
    record <- time.Now() 
} 

func (self Queue) pop(record chan interface{}) { 
    // need pop counter 
    <- record 
} 

func main() { 
    runtime.GOMAXPROCS(runtime.NumCPU()) 
    //record chan 
    record := make(chan interface{},1000000) 
    //finish flag chan 
    finish := make(chan bool) 
    queue := new(Queue) 
    for i:=0; i<10; i++ { 
     go func() { 
      for j:=0; j<DATA_SIZE_PER_THREAD; j++ { 
       queue.push(record) 
      } 
      finish<-true 
     }() 
    } 
    for i:=0; i<10; i++ { 
     go func() { 
      for j:=0; j<DATA_SIZE_PER_THREAD; j++ { 
       queue.pop(record) 
      } 
      finish<-true 
     }() 
    } 
    for i:=0; i<20; i++ { 
     <-finish 
    } 
} 

答えて

11

修正する必要があることがいくつかあります。

  • キュー型のメソッドには、ポインタ受信者が必要です。それ以外の場合は、すべてのメソッド が現在のキュータイプのコピーを作成し、キューフィールドの変更はすべて メソッド呼び出し自体を超えて持続しません。

  • すべてのルーチンが完了するのを待って、sync.WaitGroupを使用して実行できます。この は、具体的に設計されたものです。

  • sync/atomicパッケージを使用して、キュータイプ内でスレッドセーフなプッシュ/ポップカウンタを維持するには、 を使用できます。

スピードは、あなたの例から、あなたが達成しようとしていることはかなりわかりません。少し詳しく説明すれば、どんな最適化も出てくるかもしれません。ここで

は、私はあなたのコードから変形例である:1に疑問を

package main 

import (
    "log" 
    "runtime" 
    "sync" 
    "sync/atomic" 
    "time" 
) 

const SizePerThread = 10000000 

type Queue struct { 
    records string 
    count int64 
} 

func (q *Queue) push(record chan interface{}) { 
    record <- time.Now() 

    newcount := atomic.AddInt64(&q.count, 1) 
    log.Printf("Push: %d", newcount) 
} 

func (q *Queue) pop(record chan interface{}) { 
    <-record 

    newcount := atomic.AddInt64(&q.count, -1) 
    log.Printf("Pop: %d", newcount) 
} 

func main() { 
    var wg sync.WaitGroup 

    runtime.GOMAXPROCS(runtime.NumCPU()) 

    record := make(chan interface{}, 1000000) 
    queue := new(Queue) 

    // We are launching 20 goroutines. 
    // Let the waitgroup know it should wait for as many 
    // of them to finish. 
    wg.Add(20) 

    for i := 0; i < 10; i++ { 
     go func() { 
      defer wg.Done() 

      for j := 0; j < SizePerThread; j++ { 
       queue.push(record) 
      } 
     }() 

     go func() { 
      defer wg.Done() 

      for j := 0; j < SizePerThread; j++ { 
       queue.pop(record) 
      } 
     }() 
    } 

    // Wait for all goroutines to finish. 
    wg.Wait() 
} 
+0

ありがとう@jimt、しかし、あなたが意味することを**私はかなり理解していない**キュータイプは、ポインタ受信機を持っている必要があります**、あなたは私にゴランのドキュメントのリンクを与えることができますか?私は何も見つけることができません、再びありがとう。 – MrROY

+0

@MroY:Effective Goのこのセクションでは、その違いについて説明します:http://golang.org/doc/effective_go.html#pointers_vs_values本質的には、レシーバが(T)の場合、メソッドは呼び出されたオブジェクトの*コピー*を取得するため、変更できません。受信機が(* T)の場合は、それを指すポインタを取得します。 –

+0

ゴルーチンの数がコンパイル時に厳密に知られていない場合、作成されたそれぞれのゴルーチンで 'wg.Add(1)' 'defer.wg.Done()を呼び出さない理由がありますか? – matthias

-4

回答:JIMTが示唆したように、同期/原子はあなたに有用であり得る、アトミックカウンタを更新するための機能を持っています。

2を疑問視する

回答:プログラムよりefficent方法であなたのプログラムと同じ出力を生成し

package main 
func main() {} 

を使用し、まだ良くDATA_SIZE_PER_THREADの値を減らしますか。

本当に、あなたはいくつかの概念を探求するための小さなプログラムを書いていると思います。しかし、あなたのプログラムにはいくつかの問題があります。これはスピードを心配する時間ではなく、いくつかの基本的な概念を学ぶ時です。

+0

役に立たない答えはまったくありません。 – OneOfOne

関連する問題