Добавление параллелизма Golang вызовет случайную панику

Я использую golang append в goroutine в среде продукта. Я знаю, что не должен его использовать, потому что он небезопасен для параллелизма. Но при его использовании сталкиваюсь с паникой. Это довольно странно. У кого-нибудь есть идеи?

package main

import (
    "sync"
)

func TestAppend() (result []int) {
    var wg sync.WaitGroup
    //result = make([]int, 0, 10) //set enough capacity first, will not add capacity, it will not panic
    for i := 0; i < 100; i++ {
        v := i
        wg.Add(1)
        go func() {
            defer wg.Done()
            result = append(result, v)
        }()
    }

    wg.Wait()
    return result
}

func main() {
    for a := 0; a < 100000; a++ {
        res := TestAppend()
        println("len(res):", len(res))
    }
}

версия Golang - 1.4.

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

panic: runtime error: invalid memory address or nil pointer dereference
[signal SIGSEGV: segmentation violation code=0x1 addr=0x0 pc=0x10577ef]

goroutine 8996815 [running]:
main.TestAppend.func1(0xc000092000, 0xc00000c020, 0x9)
        /Users/left-pocket/go-practice/concurrency_append/main.go:15 +0x6f
created by main.TestAppend
        /Users/left-pocket/go-practice/concurrency_append/main.go:13 +0xa6

Process finished with exit code 2

Я отлаживаю код, обнаружил, что код паники

func growslice(et *_type, old slice, cap int) slice {
    ...
    memmove(p, old.array, lenmem)
    ...
}

Похоже, у memmove есть шанс запаниковать при использовании добавления в параллелизме. Но не уверен, в чем причина. У кого-нибудь есть идеи?

"версия golang - 1.4" - я бы порекомендовал вам обновить до 1.16, хотя это, вероятно, не решит вашу проблему.
mkopriva 30.03.2021 10:58

Итак, вы знаете, что это небезопасно для параллелизма, и затем вы спрашиваете, почему возникает паника ... ??

super 30.03.2021 11:00

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

leftpocket 30.03.2021 11:06

«Но просто хочу понять основную причину, которая вызывает панику» Основная причина находится в верхней части сообщения об ошибке: «недопустимый адрес памяти или разыменование нулевого указателя» Что неясно по этой причине?

Volker 30.03.2021 11:28

Основная причина в том, что несинхронизированное чтение и запись в общую переменную несколькими читателями и писателями приводит к неопределенному поведению. Выполняемые инструкции больше не синхронизируются с состоянием памяти. В вашем случае это приводит к исключению nil ptr, в других случаях это может незаметно заменить вызов функции во время выполнения (software.intel.com/content/www/us/en/develop/blogs/…). Может быть, вы хотите узнать больше о внутреннем устройстве компьютерных языков, я не уверен, что это подходящее место, но мне действительно нравится этот вопрос.

mh-cbon 30.03.2021 12:17

Обратите внимание, что значение заголовка среза состоит из трех частей: указателя (на основание некоторой области в памяти, которая может содержать значения), длины и емкости. При использовании result = append(result, v) функция append () возвращает, по крайней мере, логически, новое значение заголовка фрагмента - другими словами, новый набор из трех значений - и эти три значения могут быть «подключены» к переменной в любом порядке. Если порядок следующий: «сначала новая емкость, затем новая длина и / или указатель», второй append может решить, что существующий указатель (возможно, ноль) имеет место для нескольких элементов, и выбрать запись в ноль.

torek 30.03.2021 12:36

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

torek 30.03.2021 12:37

Это паника, потому что это гонка данных ... Вы уже ответили на свой вопрос. software.intel.com/content/www/us/en/develop/blogs/…

bronze man 30.03.2021 14:09
Создание API ввода вопросов на разных языках программирования (Python, PHP, Go и Node.js)
Создание API ввода вопросов на разных языках программирования (Python, PHP, Go и Node.js)
API ввода вопросов - это полезный инструмент для интеграции моделей машинного обучения, таких как ChatGPT, в приложения, требующие обработки...
5
8
44
0

Другие вопросы по теме