Как исправить ошибку «panic close of closed channel»?

Ссылка скопирована
Go
2 ответов

Мне на курсах дали задачу:

"Напишите программу для подсчета суммы чисел в слайсе параллельно, используя горутины. Программа должна разделять исходный слайс на несколько слайсов и затем находить сумму каждой части в отдельной горутине. После этого подсчитывается финальная сумма. Программа должна реализовать следующий интерфейс:

type Summer interface{ // функция для нахождения суммы чисел func ProcessSum( // функция, которая будет вызываться для нахождения суммы части слайса. // результат суммы записать в result summer func(arr []int, result chan<- int), // слайс с числами, сумму которых нужно найти nums []int, // сколько элементов в одной части (последняя часть может быть меньше) сhunkSize int, ) (int, error) // вернуть сумму чисел }

type Summer interface{ // функция для нахождения суммы чисел func ProcessSum( // функция, которая будет вызываться для нахождения суммы части слайса. // результат суммы записать в result summer func(arr []int, result chan<- int), // слайс с числами, сумму которых нужно найти nums []int, // сколько элементов в одной части (последняя часть может быть меньше) сhunkSize int, ) (int, error) // вернуть сумму чисел }

Также нужно реализовать функцию SumChunk(arr []int, result chan<- int), которая будет вызываться для нахождения суммы части слайса (summer). В случае возникновения ошибок верните 0 и возникшую ошибку."

Вот мой код:

package main  import (     "fmt" )  type Summer interface {     ProcessSum(summer func(arr []int, result chan&lt;- int), nums []int, chunkSize int) (int, error) }  func SumChunk(arr []int, result chan&lt;- int) {     go func() {         defer close(result)         var sum int         for i := range arr {             sum += arr[i]         }         result &lt;- sum     }() }  func ProcessSum(summer func(arr []int, result chan&lt;- int), nums []int, chunkSize int) (int, error) {     if chunkSize &lt;= 0 {         return 0, fmt.Errorf("invalid chunkSize")     }      var sum int     out := make(chan int)      for i := 0; i &lt; len(nums); i += chunkSize {         end := i + chunkSize         if end &gt; len(nums) {             end = len(nums)         }         go summer(nums[i:end], out)                  sum += &lt;-out     }     close(out)     return sum, nil }

package main import ( "fmt" ) type Summer interface { ProcessSum(summer func(arr []int, result chan&lt;- int), nums []int, chunkSize int) (int, error) } func SumChunk(arr []int, result chan&lt;- int) { go func() { defer close(result) var sum int for i := range arr { sum += arr[i] } result &lt;- sum }() } func ProcessSum(summer func(arr []int, result chan&lt;- int), nums []int, chunkSize int) (int, error) { if chunkSize &lt;= 0 { return 0, fmt.Errorf("invalid chunkSize") } var sum int out := make(chan int) for i := 0; i &lt; len(nums); i += chunkSize { end := i + chunkSize if end &gt; len(nums) { end = len(nums) } go summer(nums[i:end], out) sum += &lt;-out } close(out) return sum, nil }

Как мне исправить ошибку "panic: close of closed channel", которая возникает при проверке? Помогите пожалуйста :(

Дополнительно:

как минимум перестать закрывать канал в SumChunk

  • да и параллельной работы не будет из-за кривого использования канала — его нужно или сделать буфферизированным на количество чанков, или сумму считать в отдельном цикле, после запуска всех горутин

    да и зачем ещё один запуск горутины в SumChunk с кложурой не совсем понятно

  • Советую посмотреть как реализуется worker pool на го.

    Например тут https://gobyexample.com/worker-pools

    Но есть еще много хороших реализаций под разные задачи, поищите, гляньте что больше подходит вам и посмотрите, как оно работает.

  • Александр Павлюк, спасибо за помощь!
  • Нужно решить такую задачу?

    Опишите проблему, и специалист поможет с настройкой, исправлением ошибки или доработкой сайта. Подберём понятный план работ без лишней переписки.

    Заказать помощь
    Лучший ответ
    1
    Юрий Linux Ответ

    Ошибка "panic close of closed channel" возникает в Go, когда программа пытается закрыть канал, который уже был закрыт. Эта ошибка часто возникает из-за неправильного использования каналов в многопоточной среде.

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

    Пример неправильного использования канала:

    package main
     
    import "fmt"
     
    func main() {
        ch := make(chan int)
     
        go func() {
            ch &lt;- 1
            close(ch)
        }()
     
        close(ch)
        fmt.Println(&lt;-ch)
    }

    package main import "fmt" func main() { ch := make(chan int) go func() { ch &lt;- 1 close(ch) }() close(ch) fmt.Println(&lt;-ch) }

    В данном примере канал закрывается дважды: сначала в горутине, а затем в основной функции. Из-за этого возникает ошибка "panic close of closed channel".

    Для исправления данной ошибки, следует переписать код следующим образом:

    package main
     
    import "fmt"
     
    func main() {
        ch := make(chan int)
     
        go func() {
            ch &lt;- 1
            close(ch)
        }()
     
        for i := range ch {
            fmt.Println(i)
        }
    }

    package main import "fmt" func main() { ch := make(chan int) go func() { ch &lt;- 1 close(ch) }() for i := range ch { fmt.Println(i) } }

    В данном примере канал закрывается только один раз, после того, как все операции чтения из канала были завершены. Таким образом, мы избегаем ошибки "panic close of closed channel".

    Помните, что правильное использование каналов в Go является ключом к предотвращению подобных ошибок. Внимательно следите за жизненным циклом канала и убедитесь, что он используется правильно в многопоточной среде.

    Другие ответы (1) Ответить на вопрос
    Роман IT

    Для исправления ошибки "panic close of closed channel" вам необходимо убедиться, что вы правильно управляете закрытием канала в вашем коде. Эта ошибка обычно возникает, когда вы пытаетесь закрыть канал, который уже был закрыт ранее.

    Один из способов избежать этой ошибки - это использовать механизм синхронизации, такой как WaitGroup, для управления закрытием канала. Например, вы можете создать WaitGroup, добавить количество горутин, которые будут читать из канала, и дождаться их завершения перед закрытием канала.

    Вот пример кода на языке программирования Go, демонстрирующий это:

    package main
     
    import (
        "fmt"
        "sync"
    )
     
    func main() {
        ch := make(chan int)
        var wg sync.WaitGroup
     
        // добавляем количество горутин
        wg.Add(1)
     
        go func() {
            defer wg.Done()
            for i := range ch {
                fmt.Println(i)
            }
        }()
     
        // отправляем данные в канал
        ch &lt;- 1
        ch &lt;- 2
     
        // закрываем канал после завершения работы горутины
        go func() {
            wg.Wait()
            close(ch)
        }()
     
        // ждем завершения всех горутин
        wg.Wait()
    }

    package main import ( "fmt" "sync" ) func main() { ch := make(chan int) var wg sync.WaitGroup // добавляем количество горутин wg.Add(1) go func() { defer wg.Done() for i := range ch { fmt.Println(i) } }() // отправляем данные в канал ch &lt;- 1 ch &lt;- 2 // закрываем канал после завершения работы горутины go func() { wg.Wait() close(ch) }() // ждем завершения всех горутин wg.Wait() }

    Если вы все еще сталкиваетесь с ошибкой "panic close of closed channel", убедитесь, что вы не закрываете канал более одного раза в вашем коде, и что все горутины, читающие из канала, завершают свою работу перед закрытием канала.

    комментарий

    Ваш адрес email не будет опубликован. Обязательные поля помечены *

    Вам также может быть интересно