2015-12-21 22 views
7

Belirli bir noktada, örneğin tüm URL'ler getirildiğinde, belirli bir noktada senkronize etmek için bazı goroutine gitmek istediğim bir duruma rastladım. Sonra hepsini koyabilir ve bunları belirli bir sırayla gösterebiliriz.Sync.WaitGroup.wait kullanırken bir zaman aşımı nasıl uygulanır?

Bu geliyor bariyer olduğunu düşünüyorum. O sync.WaitGroup ile go içindedir. Ancak, gerçek durumda, tüm alım işleminin kısa sürede başarılı olacağından emin olamayız. Bu yüzden, getirme işlemleri için wait zaman aşımına uğramak istiyorum.

Golang'a yeni başlayan biriyim, bu yüzden birisi bana biraz tavsiye verebilir mi?


Ne ben arıyorum şu şekildedir:

wg := &sync.WaigGroup{} 
    select { 
    case <-wg.Wait(): 
    // All done! 
    case <-time.After(500 * time.Millisecond): 
    // Hit timeout. 
    } 

Ben Channel desteklemeyen Wait biliyorum.

+0

Eğer bir döngü ya aracılığıyla bunu yapıyor gibi demeniz bekleme grupları ve malzeme ekleyerek nasıl gönderebilir miyim ?? – Datsik

+0

Olası kopyası [Timeout for WaitGroup.Wait()] (http://stackoverflow.com/questions/32840687/timeout-for-waitgroup-wait) – jab

cevap

8

Tek isteğiniz temiz seçiminizse, bir işlevi çağıran bir rutini oluşturarak ve bir kez bittiğinde kanalda kapatıp/göndererek engelleme işlevini bir kanala kolayca dönüştürebilirsiniz. Eğer iş mantığı ile eşzamanlılık mantığı karıştırma önlemek istiyorsanız

done := make(chan struct{}) 
go func() { 
    wg.Wait() 
    close(done) 
}() 

select { 
case <-done: 
// All done! 
case <-time.After(500 * time.Millisecond): 
// Hit timeout. 
} 
+0

Bu bana iyi görünüyor. – andy

0

Bunu yapmanın bir başka yolu da dahili olarak izlemek, sorunuzu sınırlamaktır ancak sizin için çalışmayı yeniden düzenleyemeseniz bile bir döngüde goroutinesinize başladığınızı varsayacağım. ancak bu 2 örneklerden birini yapabileceği, ilki bireysel olarak zaman aşımına uğramasına her isteği zaman aşımına uğrar ve ikincisi istekleri topluluğunun tamamını aşımı ve çok fazla zaman

var wg sync.WaitGroup 
wg.Add(1) 
go func() { 
    success := make(chan struct{}, 1) 
    go func() { 
     // send your request and wait for a response 
     // pretend response was received 
     time.Sleep(5 * time.Second) 
     success <- struct{}{} 
     // goroutine will close gracefully after return  
     fmt.Println("Returned Gracefully") 
    }() 

    select { 
    case <-success: 
     break 
    case <-time.After(1 * time.Second): 
     break 
    } 

    wg.Done() 
    // everything should be garbage collected and no longer take up space 
}() 

wg.Wait() 

// do whatever with what you got  
fmt.Println("Done") 
time.Sleep(10 * time.Second) 
fmt.Println("Checking to make sure nothing throws errors after limbo goroutine is done") 

geçtiyse hareket Ya eğer olacak TÜM isteklerinizi zaman aşımına uğramak için genel bir kolaylık istersiniz

var wg sync.WaitGroup 
waiter := make(chan int) 
wg.Add(1) 
go func() { 
    success := make(chan struct{}, 1) 
    go func() { 
     // send your request and wait for a response 
     // pretend response was received 
     time.Sleep(5 * time.Second) 
     success <- struct{}{} 
     // goroutine will close gracefully after return  
     fmt.Println("Returned Gracefully") 
    }() 

    select { 
    case <-success: 
     break 
    case <-time.After(1 * time.Second): 
     // control the timeouts for each request individually to make sure that wg.Done gets called and will let the goroutine holding the .Wait close 
     break 
    } 
    wg.Done() 
    // everything should be garbage collected and no longer take up space 
}() 

completed := false 
go func(completed *bool) { 
    // Unblock with either wait 
    wg.Wait() 
    if !*completed { 
     waiter <- 1   
     *completed = true 
    }  
    fmt.Println("Returned Two") 
}(&completed) 

go func(completed *bool) { 
    // wait however long 
    time.Sleep(time.Second * 5) 
    if !*completed { 
     waiter <- 1   
     *completed = true 
    }  
    fmt.Println("Returned One") 
}(&completed) 


// block until it either times out or .Wait stops blocking 
<-waiter 

// do whatever with what you got  
fmt.Println("Done") 
time.Sleep(10 * time.Second) 
fmt.Println("Checking to make sure nothing throws errors after limbo goroutine is done") 
012 senin WaitGroup senkronize kalacak ve belirsizlik içinde kalan herhangi goroutines olmaz

Bu şekilde

http://play.golang.org/p/g0J_qJ1BUT

etrafında değişkenleri değiştirebilir burada denemek o farklı

Edit çalıştığını görmek: hattayım mobil Herkes biçimlendirmeyi düzeltebilecekse, teşekkürler.

0

engellemeden, bütün sonuçları alacak kadar bir tamponlu kanala sonuçlarınızı gönderin, ana iş parçacığı için seçim döngü onları okumak:

func work(msg string, d time.Duration, ret chan<- string) { 
    time.Sleep(d) // Work emulation. 
    select { 
    case ret <- msg: 
    default: 
    } 
} 

// ... 

const N = 2 
ch := make(chan string, N) 

go work("printed", 100*time.Millisecond, ch) 
go work("not printed", 1000*time.Millisecond, ch) 

timeout := time.After(500 * time.Millisecond) 
loop: 
for received := 0; received < N; received++ { 
    select { 
    case msg := <-ch: 
     fmt.Println(msg) 
    case <-timeout: 
     fmt.Println("timeout!") 
     break loop 
    } 
} 

Bahçesi: http://play.golang.org/p/PxeEEJo2dz. Ayrıca bkz: Go Concurrency Patterns: Timing out, moving on.

+0

Burada engellenmeyen bir gönderime neden gerek duyulmadığından emin olun, yalnızca Tampon büyüklüğünde bir güvenlik önlemi çalışan sayısıyla uyuşmuyor. Aksi takdirde, sayım (döngü için önerilir), işçiler bir kanalda bir şey üretirken, “WaitGroup” dan daha iyi bir çözümdür. – tomasz

0

, bunu size yardımcı olmak için bu kütüphaneyi https://github.com/shomali11/parallelizer yazdı. Eşzamanlılık mantığını içine alır ve bu konuda endişelenmenize gerek yoktur.Yani örnekteki

:

package main 

import (
    "github.com/shomali11/parallelizer" 
    "fmt" 
) 

func main() { 
    urls := []string{ ... } 
    results = make([]*HttpResponse, len(urls) 

    options := &Options{ Timeout: time.Second } 
    group := parallelizer.NewGroup(options) 
    for index, url := range urls { 
     group.Add(func(index int, url string, results *[]*HttpResponse) { 
      return func() { 
       ... 

       results[index] = &HttpResponse{url, response, err} 
      } 
     }(index, url, &results)) 
    } 

    err := group.Run() 

    fmt.Println("Done") 
    fmt.Println(fmt.Sprintf("Results: %v", results)) 
    fmt.Printf("Error: %v", err) // nil if it completed, err if timed out 
} 
İlgili konular