A
A
Alex Plotnikov2018-06-13 00:08:25
go
Alex Plotnikov, 2018-06-13 00:08:25

Goutins, channels, not fully working out, how to figure it out?

Greetings, I just started learning go and immediately got stuck on channels and goroutines. I'll give you the code right now

func main() {

  chanUrls := make(chan string, 100)
  chanRes := make(chan http.Response, 100)
  zipChan := make(chan Gallery, 100)
        
        for url := range Urls{
                chanUrls <- url
       }


  go httpGet(chanUrls, chanRes)
  go parser(chanRes, zipChan)

  for index := 0; index < 2; index++ {
    go zipMaker(zipChan)
  }

       defer close(zipChan)

  for range zipChan {
  }
}

func httpGet(chanUrls <-chan string, chanRes chan<- http.Response) {
      //получаем урл, отправляем response дальше
}

func parser(chanRes <-chan http.Response, zipChan chan<- Gallery) {
  for resp := range chanRes {
           //парсим данные, создаем структуру, все как положено и отправляем дальше
     zipChan <- gallery
       }
}

func zipMaker(zipChan <-chan Gallery) {
  for gallery := range zipChan {
          //тут качаем картинки из урлов, которые есть в срезе gallery.imgUrls , архивируем
        }
}

It seems that everything is simple and clear, if instead of real work in the zipMaker function we just do fmt.Println (gallery), then everything works as expected, but as soon as we start doing the work, only two tasks are performed (or as many as the zipMaker gurotin is running) , then everything just stops, without exiting the program.
Please tell me, I understand that there is a problem in the zipChan queue and it discards everything, because two goroutines are occupied, but it's with a buffer, what's wrong?

Answer the question

In order to leave comments, you need to log in

1 answer(s)
N
Nikita Shoshin, 2018-06-13
@TrueDevs

Your program terminates before it has had zipMaker()time to process all the data: the function mainterminates immediately after the loop terminates.
There are several options for solving this problem, which one to choose depends on the task:
1) if your program should work all the time, then you can simply block its execution. For example, like this:

func main() {
     // your code

    locker := make(chan struct{})
    <-locker
}

2) if you need to process a finite number of images, then you need to rework the code. In my opinion, it is not necessary to call httpGet()in parser()goroutines either. It's better to return []Gallery, then iterate over it and call the goroutine for each element. In this case, you need to use sync.WaitGroup. The code will look something like this:
package main

import (
    "log"
    "sync"
    "time"
)

// Для удобства
type Gallery int

func main() {
    // То, что должна вернуть функция parser()
    results := []Gallery{5, 6, 7, 8}

    var wg sync.WaitGroup
    for _, r := range results {
        wg.Add(1)
        go zipMaker(r, &wg)
    }
 
    log.Println("Wait")
    // Ждём выполнения горутин
    wg.Wait()
    // "Done" напечатается через 2 секунды после "Wait"
    log.Println("Done")
}

func zipMaker(g Gallery, wg *sync.WaitGroup) {
    defer wg.Done()
    // your code

    time.Sleep(time.Second * 2)
}

sync.WaitGroupallows you to wait for all data to be processed. You can read more here .

Didn't find what you were looking for?

Ask your question

Ask a Question

731 491 924 answers to any question