2012-09-04 10 views
7

Push ve pop işlevlerine sahip bir kuyruk yapısını yapmaya çalışıyorum.Golang'ın goroutini kullanırken nasıl bir sayaç uygulanır?

Aşağıdaki kodda yaptığım gibi 10 iş parçacığı push ve diğer 10 iş parçacığı pop verisini kullanmalıyım.

Sorular: 1. Ne kadar ittiğimi/attığımı yazdırmam gerekiyor, ancak bunu nasıl yapacağımı bilmiyorum. 2. Kodumu hızlandırmak için zaten var mı? kod benim için çok yavaş.

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 
    } 
} 

cevap

11

Düzeltmeniz gereken birkaç şey var.

  • Kuyruk türü yöntemleri, işaretçi alıcılarına sahip olmalıdır. Aksi takdirde, her bir yöntem çağrısı, geçerli sıra türünün bir kopyasını oluşturur ve sıra alanlarındaki herhangi bir değişiklik, yöntemin kendisinin ötesine geçmeyecek şekilde olacaktır. Tüm rutinlerin tamamlanmasını beklerken, sync.WaitGroup kullanarak yapılabilir. Bu özellikle bunun için tasarlandığı şeydir.

  • sıra türü içinde bir evreli bas/aç sayacı sync/atomic paketi kullanılarak yapılabilir muhafaza edilmiştir.

Hız gittiğine gelince, örneğinizden, neyi başarmaya çalıştığınızdan emin değilim. Bunu biraz daha ayrıntılı hale getirirseniz, herhangi bir optimizasyon ortaya çıkabilir.

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

Teşekkürler @jimt, ama tam olarak ne demek istediğini anlamadım ** Kuyruk tipi işaretçi alıcıları olmalı **, bana golang'ın dokümanı hakkında bir link verebilir misiniz? Ben bulamıyorum, tekrar teşekkürler. – MrROY

+0

@MrROY: Effective Go'nun bu bölümü şu farkı tartışıyor: http://golang.org/doc/effective_go.html#pointers_vs_values. Esas olarak, eğer alıcı (T) ise, yönteminiz çağrılan nesnenin bir kopyasını * alır ve bu nedenle değiştiremez. Alıcı (* T) ise, ona bir işaretçi alır. –

+0

Go-rutines sayısının derleme zamanında kesin olarak bilinmediği durumlarda, oluşturulan her bir üründe b wg.Add (1) ' ' defer.wg.Done() 'ı çağırmamanız için herhangi bir neden var mı? – matthias

-4

Cevap sorgulamaya 1: Burada

Ben senin kodundan değiştirilmiş bir örnektir jimt önerildiği gibi senkron/atomik atomik sizin için yararlı olabilecek bir sayaç, güncellenmesi için işlevlere sahiptir.

Cevap 2. soruya: daha iyisi DATA_SIZE_PER_THREAD değerini azaltın veya program daha verimli bir şekilde program ile aynı çıktıyı üretir

package main 
func main() {} 

kullanın.

Gerçekten de, bazı kavramları keşfetmek için küçük bir program yazmış olduğunu anlıyorum. Ancak programınız bir dizi sorun içeriyor. Bu, hız hakkında endişelenme zamanı değil, bazı temel kavramları öğrenmenin zamanı.

+0

Hiç yardımcı bir cevap değil. – OneOfOne