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

huangapple go评论118阅读模式
英文:

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

问题

你好,这是我的示例Go Playground链接:https://go.dev/play/p/dUUsf6OXt1x

  1. input := []int{1, 2, 3, 4, 5, 6, 7, 8}
  2. wg := sync.WaitGroup{}
  3. var result []int
  4. for i, num := range input {
  5. wg.Add(1)
  6. go func(num, i int) {
  7. if num%2 == 0 {
  8. result = append(result, num)
  9. }
  10. wg.Done()
  11. }(num, i)
  12. }
  13. wg.Wait()
  14. fmt.Println(result)

我的目标是以正确的顺序得到结果 2,4,6,8

不幸的是,由于我使用的是追加操作而不是分配给特定切片索引,有时会丢失数据(由于数据竞争),并以不正确的顺序接收结果。

问题在于输入是动态的,它具有无限数量的值,我不知道有多少输入的值无法通过 num%2 == 0 的过滤。

请问你能指导我如何在保持顺序的同时并发地追加筛选结果并保存所有数据吗?

英文:

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

  1. input := []int{1, 2, 3, 4, 5, 6, 7, 8}
  2. wg := sync.WaitGroup{}
  3. var result []int
  4. for i, num := range input {
  5. wg.Add(1)
  6. go func(num, i int) {
  7. if num%2 == 0 {
  8. result = append(result, num)
  9. }
  10. wg.Done()
  11. }(num, i)
  12. }
  13. wg.Wait()
  14. 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

答案1

得分: 1

根据@mkopriva的建议,我通过以下方式解决了这个问题:
不幸的是,我有两个循环而不是一个,而且我不能与第二个循环并发,因为我会遇到与第一个循环相同的问题。

  1. events := []int{1, 2, 3, 4, 5, 6, 7, 8}
  2. channels := make([]chan *int, 0)
  3. // 并发开始
  4. for _, event := range events {
  5. channel := make(chan *int)
  6. go response(event, channel)
  7. channels = append(channels, channel)
  8. }
  9. // 收集响应
  10. var response []int
  11. for i := range channels {
  12. result := <-channels[i]
  13. if result%2 == 0 {
  14. response = append(response, result)
  15. }
  16. }
  17. // 打印响应
  18. log.Printf("channel response %v", response)

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

嗯,这是最好的方式吗?

英文:

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.

  1. events := []int{1, 2, 3, 4, 5, 6, 7, 8}
  2. channels := make([]chan *int, 0)
  3. // start concurrently
  4. for _, event := range events {
  5. channel := make(chan *int)
  6. go response(event, channel)
  7. channels = append(channels, channel)
  8. }
  9. // collect response
  10. var response []int
  11. for i := range channels {
  12. result := *&lt;-channels[i]
  13. if result%2 == 0 {
  14. response = append(response, result)
  15. }
  16. }
  17. // print response
  18. log.Printf(&quot;channel response %v&quot;, response)

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

Hmmmm is this the best way?

huangapple
  • 本文由 发表于 2022年10月14日 13:24:46
  • 转载请务必保留本文链接:https://go.coder-hub.com/74064646.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定