Зачем использовать канал в этой функции? - PullRequest
0 голосов
/ 08 ноября 2019

Я изучал блог о сроках использования подпрограмм, и я видел пример, вставленный ниже, со строки 61 до строки 65. Но я не понимаю цели использования канала здесь.

Похоже, он перебирает каналы, чтобы получить сообщение внутри go-рутины. Но почему бы не использовать строковый массив напрямую?

58 func findConcurrent(goroutines int, topic string, docs []string) int {
59     var found int64
60
61     ch := make(chan string, len(docs))
62     for _, doc := range docs {
63         ch <- doc
64     }
65     close(ch)
66
67     var wg sync.WaitGroup
68     wg.Add(goroutines)
69
70     for g := 0; g < goroutines; g++ {
71         go func() {
72             var lFound int64
73             for doc := range ch {
74                 items, err := read(doc)
75                 if err != nil {
76                     continue
77                 }
78                 for _, item := range items {
79                     if strings.Contains(item.Description, topic) {
80                         lFound++
81                     }
82                 }
83             }
84             atomic.AddInt64(&found, lFound)
85             wg.Done()
86         }()
87     }
88
89     wg.Wait()
90
91     return int(found)
92 }

Ответы [ 2 ]

2 голосов
/ 08 ноября 2019

Этот код предоставляет пример способа распределения работы (поиск строк в документах) среди нескольких goRoutines. В основном, код запускается goroutines и передает им документы для поиска по каналу.

Но почему бы не использовать массив строк напрямую?

Можно было бы использоватьстроковый массив и переменная (давайте назовем это count), чтобы отследить, к какому элементу массива вы подходите. У вас будет такой код (немного затянутый, чтобы продемонстрировать точку):

for {
   if count > len(docarray) {
      break;
   }
   doc := docarray[count]
   count++
   // Process the document
}

Однако вы столкнетесь с проблемами синхронизации. Например, что произойдет, если две подпрограммы go (работающие на разных процессорных ядрах) получат if count > len(docarray) одновременно? Без чего-либо, что могло бы предотвратить это, они оба могли бы в конечном итоге обработать один и тот же элемент в срезе (и, возможно, пропустить следующий элемент, потому что оба они запускают count++).

Синхронизация процессов является сложной и проблемы могут быть очень сложнымиотлаживать. Использование каналов скрывает от вас большую часть этой сложности и повышает вероятность того, что ваш код будет работать должным образом (он не решает все проблемы; обратите внимание на использование atomic.AddInt64(&found, lFound) в примере кода, чтобы предотвратить другую потенциальную проблему, которая может возникнуть в результатеодновременная запись нескольких переменных в переменную).

0 голосов
/ 08 ноября 2019

Автор, кажется, просто использует надуманный пример, чтобы проиллюстрировать, как работают каналы. Возможно, ему хотелось бы привести более реалистичный пример. Но он говорит:

Примечание: есть несколько способов и вариантов, которые вы можете использовать при написании параллельной версии add. Не зацикливайтесь на моей конкретной реализации в это время. Если у вас есть более читаемая версия, которая работает так же или лучше, я бы хотел, чтобы вы поделились ею.

Так что, очевидно, он не пытался написать лучший код дляработа, просто кое-что, чтобы проиллюстрировать его точку зрения.

...