Wie man das Go-Vorstellungsgespräch besteht: Top-Fragen und Antworten

Online Python-Trainer für Anfänger

Lernen Sie Python einfach ohne theoretische Überlastung. Lösen Sie praktische Aufgaben mit automatischer Überprüfung und schreiben Sie Code direkt im Browser.

Kurs starten

Wie man ein Go-Vorstellungsgespräch besteht: Top-Fragen mit Codebeispielen



Ein Vorstellungsgespräch für eine Go-Entwicklerposition ist nicht nur eine Überprüfung der Syntax, sondern auch ein tiefes Verständnis des Nebenläufigkeitsmodells, der Speicherverwaltung und des idiomatischen Sprachstils. In diesem Artikel haben wir die Top-10-Fragen analysiert, die am häufigsten in Golang-Vorstellungsgesprächen gestellt werden, mit detaillierten Antworten und Codebeispielen. Das Material eignet sich sowohl für Junior- als auch für Middle-Level.



1. Goroutinen vs. OS-Threads: Was ist der Unterschied?

Dies ist eine grundlegende Frage, die das Verständnis des Go-Ausführungsmodells prüft. Die Antwort sollte klar sein:

  • Stack-Größe: Eine Goroutine startet mit einem ~2 KB großen Stack, der dynamisch wächst. Ein OS-Thread hat einen festen Stack (1-8 MB).
  • Kontextwechsel: Goroutinen wechseln im Benutzerraum (Go Scheduler). Threads wechseln über einen Systemaufruf (teurer).
  • Erstellungskosten: Eine Goroutine kostet ~4 KB Speicher, ein Thread ~1 MB. Man kann Tausende von Goroutinen starten.
// Beispiel: 10000 Goroutinenfunc main() {    for i := 0; i < 10000; i++ {        go func(n int) {            fmt.Println("Goroutine", n)        }(i)    }    time.Sleep(time.Second)}


2. Channels: Gepuffert und ungepuffert

Eine Frage zum Verständnis der Synchronisation. Erklären Sie den Unterschied anhand eines Beispiels:

  • Ungepufferter Channel: Das Senden blockiert, bis der Empfang erfolgt. Garantiert Synchronität.
  • Gepufferter Channel: Das Senden blockiert nicht, solange der Puffer nicht voll ist. Ermöglicht asynchrone Übertragung.
// Ungepufferter Channelch := make(chan int)go func() { ch <- 42 }()val := <-ch // Blockiert, bis der Wert ankommt

// Gepufferter ChannelbufCh := make(chan int, 2)bufCh <- 1 // Blockiert nichtbufCh <- 2 // Blockiert nicht// bufCh <- 3 // Blockiert - Puffer ist voll


3. Select und die Verarbeitung mehrerer Channels

Die select-Anweisung ermöglicht das Warten auf mehrere Channel-Operationen. Häufig wird nach default und Timeouts gefragt:

func main() {    ch1 := make(chan string)    ch2 := make(chan string)

go func() { time.Sleep(2 * time.Second); ch1 <- "from ch1" }() go func() { time.Sleep(1 * time.Second); ch2 <- "from ch2" }()

select { case msg := <-ch1: fmt.Println(msg) case msg := <-ch2: fmt.Println(msg) case <-time.After(3 * time.Second): fmt.Println("Timeout") }}


4. Interfaces: Leeres Interface und Type Assertion

Überprüfung des Verständnisses von interface{} (any) und sicherer Typkonvertierung:

func describe(i interface{}) {    switch v := i.(type) {    case int:        fmt.Printf("Ganzzahl: %d", v)    case string:        fmt.Printf("Zeichenkette: %s", v)    default:        fmt.Printf("Unbekannter Typ: %T", v)    }}

func main() { describe(42) describe("hello") describe(3.14)}


5. Speicherverwaltung: Stack und Heap, Escape Analysis

Eine Frage zum Verständnis, wie Go entscheidet, wo Variablen platziert werden. Der Schlüsselpunkt ist die Escape Analysis:

  • Wenn der Compiler sieht, dass eine Variable nach der Rückkehr aus einer Funktion verwendet werden könnte, "entkommt" sie auf den Heap.
  • Die Verwendung von Zeigern, Interfaces und Closures führt oft zu einer Heap-Allokation.
// Variable x "entkommt" auf den Heapfunc createPointer() *int {    x := 42    return &x // x kann nicht auf dem Stack sein}


6. Defer: Ausführungsreihenfolge und Besonderheiten

Defer wird nach dem LIFO-Prinzip (Last In, First Out) ausgeführt. Argumente werden zum Zeitpunkt der Deklaration ausgewertet, nicht der Ausführung:

func main() {    x := 10    defe

Blogs

Buchempfehlungen