Никола обнови решението на 15.11.2016 06:20 (преди над 1 година)
+package main
+
+import (
+ "fmt"
+ "time"
+)
+
+type returnType struct {
+ index int
+ result string
+}
+
+func main() {
+
+ first := func() string {
+ time.Sleep(2 * time.Second)
+ return "first"
+ }
+ second := func() string {
+ time.Sleep(1 * time.Second)
+ return "second"
+ }
+ third := func() string {
+ time.Sleep(600 * time.Millisecond)
+ return "" // always a failure :(
+ }
+ fourth := func() string {
+ time.Sleep(700 * time.Millisecond)
+ return "am I last?"
+ }
+
+ fmt.Println("Starting concurrent executor!")
+ tasks := []func() string{first, second, third, fourth}
+ results := ConcurrentRetryExecutor(tasks, 2, 3)
+ for result := range results {
+ if result.result == "" {
+ fmt.Printf("Task %d returned an error!\n", result.index+1)
+ } else {
+ fmt.Printf("Task %d successfully returned '%s'\n", result.index+1, result.result)
+ }
+ }
+ fmt.Println("All done!")
+}
+
+func ConcurrentRetryExecutor(tasks []func() string, concurrentLimit int, retryLimit int) <-chan struct {
+ index int
+ result string
+} {
+ var semaphore chan struct{} = make(chan struct{}, concurrentLimit)
+ resultChannel := make(chan struct {
+ index int
+ result string
+ }, len(tasks)*retryLimit)
+ go RetryingWrapperParent(tasks, retryLimit, semaphore, resultChannel)
+ return resultChannel
+}
+
+func RetryingWrapperParent(tasks []func() string, retryLimit int, semaphore chan struct{}, resultChannel chan struct {
+ index int
+ result string
+}) {
+ for i, task := range tasks {
+ semaphore <- struct{}{}
+ go RetryingWrapper(task, i, retryLimit, semaphore, resultChannel)
+ }
+ for {
този busy loop може да се направи да не е busy ;)
А защо е проблем, че е busy? В случая искам да чакам докато се изпълнят всички задачи... има ли по-добър начин?
Видях че такъв loop монополизира едно ядро, което е доста лошо... :/ С един sleep мога да го подобря това... мисля за по-добър начин.
+ if len(semaphore) == 0 {
+ break
+ }
+ }
+ close(resultChannel)
+}
+
+func RetryingWrapper(task func() string, taskNumber int, retryLimit int, semaphore chan struct{}, resultChannel chan struct {
+ index int
+ result string
+}) {
+ returnStruct := returnType{taskNumber, ""}
+ for retryLimit > 0 {
+ returnStruct.result = task()
+ resultChannel <- returnStruct
+ if returnStruct.result != "" {
+ break
+ } else {
+ retryLimit--
+ }
+ }
+ <-semaphore
+}