A ferramenta de Golang para detectar se há um problema com o acesso simultâneo a recursos compartilhados - detector de corrida

O detector de corrida Go foi implementado com base na tecnologia de sanitizadores C / C ++ do Google. O compilador detecta todos os acessos à memória e adiciona código para monitorar o acesso (leitura ou gravação) desses endereços de memória. Quando o código está rodando, o detector de corrida pode monitorar o acesso assíncrono às variáveis ​​compartilhadas.Quando a corrida aparecer, ele irá imprimir uma mensagem de aviso. Essa tecnologia ajudou muito dentro do Google e detectou um grande número de problemas de simultaneidade com o Chromium e outros códigos. Essa tecnologia foi introduzida no Go 1.1 e 42 problemas de simultaneidade na biblioteca padrão foram descobertos imediatamente. Agora, o detector de corrida se tornou parte do processo de integração contínua do Go. Vamos ver como usar essa ferramenta.

Quando você compila, testa ou executa o código Go, pode encontrar problemas de simultaneidade adicionando o parâmetro de corrida. Por exemplo, no exemplo acima, podemos executar com o parâmetro race para verificar se há um problema de simultaneidade. Se você executar -race counter.go, uma mensagem de aviso será exibida.


示例问题代码:
 import (
        "fmt"
        "sync"
    )
    
    func main() {
    
    
        var count = 0
        // 使用WaitGroup等待10个goroutine完成
        var wg sync.WaitGroup
        wg.Add(10)
        for i := 0; i < 10; i++ {
    
    
            go func() {
    
    
                defer wg.Done()
                // 对变量count执行10次加1
                for j := 0; j < 100000; j++ {
    
    
                    count++
                }
            }()
        }
        // 等待10个goroutine完成
        wg.Wait()
        fmt.Println(count)
    }

Os resultados são os seguintes:
Insira a descrição da imagem aqui
Este aviso não apenas dirá a você que há um problema de simultaneidade, mas também informará qual goroutine tem operações de gravação para qual variável em qual linha e qual goroutine leu operações em qual variável em qual linha estão essas leituras e gravações simultâneas. A visita causou uma disputa de dados. No exemplo, goroutine 10 tem uma operação de leitura no endereço de memória 0x00c000126010 (linha 16 do arquivo counter.go), enquanto goroutine 7 tem uma operação de gravação no endereço de memória 0x00c000126010 (linha 16 do arquivo counter.go). E pode haver vários goroutines lendo e gravando ao mesmo tempo, então a mensagem de aviso pode ser muito longa. Embora essa ferramenta seja muito conveniente de usar, por causa de sua implementação, ela só pode ser detectada quando o endereço real é lido e escrito, portanto, não pode detectar problemas de corrida de dados durante a compilação. Além disso, durante a execução, ele só pode ser detectado após a corrida de dados ser acionada. Se acontecer de não ser acionado (por exemplo, um problema de corrida de dados só pode aparecer no ponto zero em 14 de fevereiro ou no ponto zero em 11 de novembro) , não é detectado. Além disso, implantar um programa com corrida on-line ainda afeta o desempenho. Execute a ferramenta go compile -race -S counter.go para visualizar o código do exemplo do contador, focando no código compilado antes e depois da contagem ++:


0x002a 00042 (counter.go:13)    CALL    runtime.racefuncenter(SB)
       ......
        0x0061 00097 (counter.go:14)    JMP     173
        0x0063 00099 (counter.go:15)    MOVQ    AX, "".j+8(SP)
        0x0068 00104 (counter.go:16)    PCDATA  $0, $1
        0x0068 00104 (counter.go:16)    MOVQ    "".&count+128(SP), AX
        0x0070 00112 (counter.go:16)    PCDATA  $0, $0
        0x0070 00112 (counter.go:16)    MOVQ    AX, (SP)
        0x0074 00116 (counter.go:16)    CALL    runtime.raceread(SB)
        0x0079 00121 (counter.go:16)    PCDATA  $0, $1
        0x0079 00121 (counter.go:16)    MOVQ    "".&count+128(SP), AX
        0x0081 00129 (counter.go:16)    MOVQ    (AX), CX
        0x0084 00132 (counter.go:16)    MOVQ    CX, ""..autotmp_8+16(SP)
        0x0089 00137 (counter.go:16)    PCDATA  $0, $0
        0x0089 00137 (counter.go:16)    MOVQ    AX, (SP)
        0x008d 00141 (counter.go:16)    CALL    runtime.racewrite(SB)
        0x0092 00146 (counter.go:16)    MOVQ    ""..autotmp_8+16(SP), AX
       ......
        0x00b6 00182 (counter.go:18)    CALL    runtime.deferreturn(SB)
        0x00bb 00187 (counter.go:18)    CALL    runtime.racefuncexit(SB)
        0x00c0 00192 (counter.go:18)    MOVQ    104(SP), BP
        0x00c5 00197 (counter.go:18)    ADDQ    $112, SP

No código compilado, foram adicionados métodos para detectar a corrida de dados, como runtime.racefuncenter, runtime.raceread, runtime.racewrite, runtime.racefuncexit, etc. Com esses comandos inseridos, a ferramenta detector de corrida Go pode detectar com êxito o problema de corrida de dados. Resumindo, inserindo algumas instruções em tempo de compilação e detectando leitura e escrita simultâneas por meio dessas instruções inseridas em tempo de execução para descobrir problemas de corrida de dados, este é o mecanismo de implementação desta ferramenta.

Acho que você gosta

Origin blog.csdn.net/csdniter/article/details/110931624
Recomendado
Clasificación