I am trying to understand how concurrency in golang works for that I am trying to process a large JSON file in batches but I am not sure when should I close my channel. Below is the code,

```
package main

import (
    "fmt"
   "os"
   "time"
)

type Order struct {
    Recipe   string         `json:"recipe"`
    PostCode string         `json:"postcode"`
    Delivery TimeWithFormat `json:"delivery"`
}

type TimeWithFormat struct {
    WeekDay   string
    StartTime time.Time
    EndTime   time.Time
    Valid   bool
}

func main() {
 input, err := os.Open("test.json")
 if err != nil {
    fmt.Println(err)
 }

concurrency := 20
inGest := make(chan []Order)
ret := make(chan map[string]int)

for x := 0; x < concurrency; x++ {
    go processRecipesWorker(inGest, ret)
}

go ParseInMemory(input, inGest)

finalMap := make(map[string]int)
for v := range ret {
    // Combine all incoming results
    for recipe, occurrence := range v {
        if v, ok := finalMap[recipe]; ok {
            finalMap[recipe] = occurrence + v
        } else {
            finalMap[recipe] = occurrence
        }
    }
}

 //Further processing on finalMap

}

func ParseInMemory(input *os.File, ingest chan []Order) {
 data, _ := ioutil.ReadAll(input)
 var orders []Order

 if err := json.Unmarshal(data, &orders); err != nil {
    log.Fatal(err.Error())
}

batch := 100000
for i := 0; i < len(orders); i += batch {
    j := i + batch
    if j > len(orders) {
        j = len(orders)
    }
    ingest <- orders[i:j]
 }
 close(ingest)
}

func processRecipesWorker(in <-chan []helpers.Order, r chan map[string]int) {
 result := make(map[string]int)
 for _, order := range <-in {
    if v, ok := result[order.Recipe]; ok {
        result[order.Recipe] = v + 1
    } else {
        result[order.Recipe] = 1
    }
 }
 r <- result
}

```

I am new to golang and concurrency if there are changes needed in my code please let me know.

Feel free to comment in case of confusion.

**EDIT**
After a suggestion from Torek code looks like below,

```
package main

import (
    "fmt"
    "os"
    "time"
)

func main() {
    input, err := os.Open("test.json")
    if err != nil {
        fmt.Println(err)
    }
    var wg sync.WaitGroup
    concurrency := 20
    inGest := make(chan []helpers.Order)
    ret := make(chan map[string]int)
    wg.Add(concurrency)
    for x := 0; x < concurrency; x++ {
        go processRecipesWorker(inGest, ret)
    }

    go ParseInMemory(input, inGest)

    go (func(wg *sync.WaitGroup) {
        wg.Wait()
        close(ret)
    })(&wg)

    finalMap := make(map[string]int)
    for v := range ret {
        // Combine all incoming results
        for recipe, occurrence := range v {
            if v, ok := finalMap[recipe]; ok {
                finalMap[recipe] = occurrence + v
            } else {
                finalMap[recipe] = occurrence
            }
        }
    }

    //Further processing on finalMap

}

func ParseInMemory(input *os.File, ingest chan []Order) {
    data, _ := ioutil.ReadAll(input)
    var orders []Order

    if err := json.Unmarshal(data, &orders); err != nil {
        log.Fatal(err.Error())
    }

    batch := 100000
    for i := 0; i < len(orders); i += batch {
        j := i + batch
        if j > len(orders) {
            j = len(orders)
        }
        ingest <- orders[i:j]
    }
    close(ingest)
}

func processRecipesWorker(in <-chan []helpers.Order, r chan map[string]int) {
    // This will get us unique recipes and there occurrences
    // FR- 1 & 2 completed
    result := make(map[string]int)
    for _, order := range <-in {
        if v, ok := result[order.Recipe]; ok {
            result[order.Recipe] = v + 1
        } else {
            result[order.Recipe] = 1
        }
    }
    r <- result
    defer wg.Done()
}

```

Now the code is not throwing deadlock but it is only processing 2M records when I have 10M records I know it is happening because of all routines calling Done() so it gets ended. But Now the question is when should I call `wg.Done()` as how should code will know the last batch is processing and we can call the `.Done()` on that.