Search code examples
goconcurrencyslicewaitgroup

In Go, How to concurrently append to slice with filtering while preserving the order and no data race


Hello here's my sample go playground https://go.dev/play/p/dUUsf6OXt1x

input := []int{1, 2, 3, 4, 5, 6, 7, 8}

wg := sync.WaitGroup{}

var result []int

for i, num := range input {
    wg.Add(1)
    go func(num, i int) {
        if num%2 == 0 {
            result = append(result, num)
        }

        wg.Done()
    }(num, i)
}
wg.Wait()

fmt.Println(result)

My goal result : 2,4,6,8 in the right order

Unfortunately on my code because I am appending instead of assigning to specific slice index, I sometimes lose data (due to data race) and receive the result in an improper order.

The problem is the input is dynamic, it has a limitless count and I have no idea how many of the values of input will not pass the filtering of num%2 == 0

Can you please guide me how to concurrently append the filtered result while preserving the order and all of data


Solution

  • Based on @mkopriva's suggestion

    I solve this by the ff : Unfortunately I have 2 loops instead of 1 and I cannot concurrent with the 2nd one because I will have the same problem as the first one.

    events := []int{1, 2, 3, 4, 5, 6, 7, 8}
    channels := make([]chan *int, 0)
    
    // start concurrently
    for _, event := range events {
        channel := make(chan *int)
        go response(event, channel)
    
        channels = append(channels, channel)
    
    }
    
    // collect response
    var response []int
    
    for i := range channels {
    
        result := *<-channels[i]
        if result%2 == 0 {
    
            response = append(response, result)
    
        }
    
    }
    
    // print response
    log.Printf("channel response %v", response)
    

    Go playground: https://go.dev/play/p/gW7nNireNLS

    Hmmmm is this the best way?