En çok sorulan 25 Go mülakat sorusu: tam geliştirici rehberi

Go mülakatlarına hâkim olmak için en çok sorulan 25 soru. Goroutine, channel, arayüz ve eşzamanlılık desenleri kod örnekleriyle.

Go mülakat soruları - Tam hazırlık rehberi

Teknik Go mülakatları dilin temel kavramlarını ölçer: eşzamanlılık, bellek yönetimi ve deyimsel desenler. Bu rehber en sık sorulan 25 soruyu ayrıntılı yanıtlar ve kod örnekleriyle ele alır.

Mülakat ipucu

Go sadeliği ve okunabilirliği önemser. Mülakat yapanlar gereksiz karmaşık çözümler yerine derin anlayışı yansıtan kısa yanıtları tercih eder.

Go dilinin temelleri

1. var ile := arasındaki fark nedir?

var bildirimi türü açıkça belirtmeyi sağlar ve paket düzeyinde de çalışır. := operatörü türü otomatik çıkarsar, ancak yalnızca fonksiyon içinde kullanılır.

declaration.gogo
package main

// Package level - var required
var globalConfig = "production"

func main() {
    // var with explicit type
    var count int = 10

    // var with type inference
    var name = "Alice"

    // Short declaration - functions only
    age := 25

    // Multiple declarations
    var (
        host = "localhost"
        port = 8080
    )
}

Fonksiyon içinde sadeliği sağlayan := tercih edilirken, paket düzeyindeki değişkenler için var zorunludur.

2. Go'nun tip sistemi nasıl çalışır?

Go statik tipleme ve tip çıkarımı kullanır. Dil; atamada kopyalanan değer tiplerini, alttaki yapıyı paylaşan referans tiplerinden ayırır.

types.gogo
package main

import "fmt"

func main() {
    // Value types - full copy
    a := [3]int{1, 2, 3}
    b := a          // Copies the array
    b[0] = 100      // Doesn't modify a
    fmt.Println(a)  // [1 2 3]

    // Reference types - share data
    slice1 := []int{1, 2, 3}
    slice2 := slice1    // Same underlying array
    slice2[0] = 100     // Also modifies slice1
    fmt.Println(slice1) // [100 2 3]

    // Maps are also references
    m1 := map[string]int{"a": 1}
    m2 := m1
    m2["a"] = 100
    fmt.Println(m1["a"]) // 100
}

Diziler değer tipidir; slice'lar, map'ler ve channel'lar referans tipidir.

3. Dizi ile slice arasındaki farkı açıkla

Diziler derleme zamanında belirlenmiş sabit boyuta sahiptir. Slice'lar ise alttaki dizi üzerinde dinamik bir görünüm sunar ve üç bileşenden oluşur: işaretçi, uzunluk ve kapasite.

arrays_slices.gogo
package main

import "fmt"

func main() {
    // Array - fixed size, value type
    arr := [5]int{1, 2, 3, 4, 5}

    // Slice - view over the array
    slice := arr[1:4]  // [2 3 4]
    fmt.Printf("len=%d, cap=%d\n", len(slice), cap(slice))
    // len=3, cap=4

    // Modifications affect original array
    slice[0] = 20
    fmt.Println(arr) // [1 20 3 4 5]

    // Direct creation with make
    dynamic := make([]int, 3, 10)
    // len=3, cap=10

    // Append may reallocate
    dynamic = append(dynamic, 1, 2, 3, 4, 5)
}

Go'da dinamik koleksiyonlar için tercih edilen tip slice'tır.

4. defer ifadesi nasıl çalışır?

defer, içeren fonksiyonun sonunda çalışacak bir fonksiyon çağrısını planlar. Ertelenen çağrılar yığına eklenir ve LIFO (son giren, ilk çıkar) sırasıyla çalıştırılır.

defer.gogo
package main

import (
    "fmt"
    "os"
)

func main() {
    // LIFO order
    defer fmt.Println("1")
    defer fmt.Println("2")
    defer fmt.Println("3")
    // Prints: 3, 2, 1
}

// Typical use case: resource cleanup
func readFile(path string) ([]byte, error) {
    file, err := os.Open(path)
    if err != nil {
        return nil, err
    }
    defer file.Close() // Always executes

    // Read file...
    return os.ReadFile(path)
}

// Caution: arguments are evaluated immediately
func deferArgs() {
    x := 10
    defer fmt.Println(x) // Captures 10
    x = 20
    // Prints: 10
}

defer panic sırasında bile yürütmeyi garanti ettiği için kaynak temizliği için idealdir.

5. Go'da arayüz nedir?

Bir arayüz bir metot kümesini tanımlar. Bu metotları uygulayan herhangi bir tip, açık bir bildirim olmadan arayüzü dolaylı olarak karşılar.

interfaces.gogo
package main

import "fmt"

// Interface definition
type Writer interface {
    Write([]byte) (int, error)
}

// Type that implicitly implements Writer
type FileLogger struct {
    path string
}

func (f *FileLogger) Write(data []byte) (int, error) {
    // Write to file
    fmt.Println("Writing to", f.path)
    return len(data), nil
}

// Empty interface - accepts any type
func printAny(v interface{}) {
    fmt.Printf("Type: %T, Value: %v\n", v, v)
}

// Type assertion
func process(w Writer) {
    // Type check
    if fl, ok := w.(*FileLogger); ok {
        fmt.Println("FileLogger with path:", fl.path)
    }
}

Arayüzlerin örtük uygulanması paketler arasında güçlü bir ayrışmayı mümkün kılar.

Eşzamanlılık ve goroutine

6. Goroutine nedir ve thread'den nasıl ayrılır?

Goroutine, Go runtime'ı tarafından yönetilen hafif bir thread'dir. Birkaç KB stack kullanır (sistem thread'inin birkaç MB'lık stack'ine kıyasla) ve Go scheduler'ı binlerce goroutine'i az sayıda sistem thread'inde çoğullar.

goroutines.gogo
package main

import (
    "fmt"
    "sync"
    "time"
)

func main() {
    var wg sync.WaitGroup

    // Launch 1000 goroutines
    for i := 0; i < 1000; i++ {
        wg.Add(1)
        go func(id int) {
            defer wg.Done()
            time.Sleep(100 * time.Millisecond)
            fmt.Printf("Goroutine %d finished\n", id)
        }(i) // Pass i by value
    }

    wg.Wait()
    fmt.Println("All goroutines completed")
}
Sık karşılaşılan tuzak

Döngü değişkenleri her zaman değer ile goroutine'lere aktarılmalıdır. Aksi halde tüm goroutine'ler aynı son değeri yakalayabilir.

7. Channel'ların nasıl çalıştığını açıkla

Channel'lar goroutine'ler arasında iletişim ve senkronizasyon sağlar. Tamponlu (kapasiteli) ya da tamponsuz (senkron) olabilirler.

channels.gogo
package main

import "fmt"

func main() {
    // Unbuffered channel - blocks until received
    ch := make(chan int)

    go func() {
        ch <- 42 // Blocks until read
    }()

    value := <-ch // Receives value
    fmt.Println(value)

    // Buffered channel - doesn't block until full
    buffered := make(chan string, 2)
    buffered <- "first"
    buffered <- "second"
    // buffered <- "third" // Would block

    fmt.Println(<-buffered) // "first"
    fmt.Println(<-buffered) // "second"
}

Tamponsuz channel'lar senkronizasyonu garanti ederken, tamponlu channel'lar zaman bakımından gevşek bağlanma sağlar.

8. select ile birden çok channel nasıl kullanılır?

select, birden fazla channel işlemini aynı anda bekler. Hazır olan ilk işlem çalıştırılır; eşitlik durumunda seçim rastgele yapılır.

select.gogo
package main

import (
    "fmt"
    "time"
)

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

    go func() {
        time.Sleep(100 * time.Millisecond)
        ch1 <- "from ch1"
    }()

    go func() {
        time.Sleep(200 * time.Millisecond)
        ch2 <- "from ch2"
    }()

    // Wait with timeout
    for i := 0; i < 2; i++ {
        select {
        case msg := <-ch1:
            fmt.Println(msg)
        case msg := <-ch2:
            fmt.Println(msg)
        case <-time.After(500 * time.Millisecond):
            fmt.Println("Timeout")
        }
    }

    // Non-blocking select with default
    select {
    case msg := <-ch1:
        fmt.Println(msg)
    default:
        fmt.Println("No message available")
    }
}

select, Go'da eşzamanlılığı zarif bir şekilde yönetmek için temel araçtır.

9. Race condition nasıl önlenir?

Race condition, birden fazla goroutine'in eşzamanlama olmaksızın paylaşılan veriye eriştiğinde ortaya çıkar. Go birkaç koruma mekanizması sunar.

race_conditions.gogo
package main

import (
    "fmt"
    "sync"
    "sync/atomic"
)

// Solution 1: Mutex
type SafeCounter struct {
    mu    sync.Mutex
    count int
}

func (c *SafeCounter) Increment() {
    c.mu.Lock()
    defer c.mu.Unlock()
    c.count++
}

// Solution 2: RWMutex for read-heavy workloads
type Cache struct {
    mu   sync.RWMutex
    data map[string]string
}

func (c *Cache) Get(key string) string {
    c.mu.RLock()         // Multiple readers allowed
    defer c.mu.RUnlock()
    return c.data[key]
}

func (c *Cache) Set(key, value string) {
    c.mu.Lock()          // Single writer
    defer c.mu.Unlock()
    c.data[key] = value
}

// Solution 3: atomic for simple counters
var atomicCounter int64

func incrementAtomic() {
    atomic.AddInt64(&atomicCounter, 1)
}

func main() {
    // Detection: go run -race main.go
    counter := SafeCounter{}
    var wg sync.WaitGroup

    for i := 0; i < 1000; i++ {
        wg.Add(1)
        go func() {
            defer wg.Done()
            counter.Increment()
        }()
    }

    wg.Wait()
    fmt.Println("Count:", counter.count)
}

Derleyici bayrağı -race, race condition'ları çalışma zamanında tespit eder.

10. Worker pool desenini açıkla

Worker pool deseni, bir kuyruktan görev işleyen sabit sayıda goroutine oluşturarak eşzamanlılığı sınırlar.

worker_pool.gogo
package main

import (
    "fmt"
    "sync"
    "time"
)

func worker(id int, jobs <-chan int, results chan<- int, wg *sync.WaitGroup) {
    defer wg.Done()
    for job := range jobs {
        fmt.Printf("Worker %d processing job %d\n", id, job)
        time.Sleep(100 * time.Millisecond) // Simulate work
        results <- job * 2
    }
}

func main() {
    const numJobs = 10
    const numWorkers = 3

    jobs := make(chan int, numJobs)
    results := make(chan int, numJobs)

    var wg sync.WaitGroup

    // Start workers
    for w := 1; w <= numWorkers; w++ {
        wg.Add(1)
        go worker(w, jobs, results, &wg)
    }

    // Send jobs
    for j := 1; j <= numJobs; j++ {
        jobs <- j
    }
    close(jobs)

    // Wait and close results
    go func() {
        wg.Wait()
        close(results)
    }()

    // Collect results
    for result := range results {
        fmt.Println("Result:", result)
    }
}

Bu desen, çok sayıda goroutine oluşturmanın getirdiği bellek ve CPU yükünü engeller.

Go mülakatlarında başarılı olmaya hazır mısın?

İnteraktif simülatörler, flashcards ve teknik testlerle pratik yap.

Hata yönetimi ve panic/recover

11. Go'da hata nasıl yönetilir?

Go istisnalar yerine hatalar için açık dönüş değerleri kullanır. Geleneksel olarak error, döndürülen son parametredir.

errors.gogo
package main

import (
    "errors"
    "fmt"
)

// Sentinel errors for comparison
var (
    ErrNotFound     = errors.New("resource not found")
    ErrUnauthorized = errors.New("access unauthorized")
)

// Custom error type
type ValidationError struct {
    Field   string
    Message string
}

func (e *ValidationError) Error() string {
    return fmt.Sprintf("validation %s: %s", e.Field, e.Message)
}

func validateAge(age int) error {
    if age < 0 {
        return &ValidationError{
            Field:   "age",
            Message: "must be positive",
        }
    }
    return nil
}

func main() {
    // Basic check
    if err := validateAge(-5); err != nil {
        // Type assertion for custom error
        var valErr *ValidationError
        if errors.As(err, &valErr) {
            fmt.Printf("Field: %s\n", valErr.Field)
        }
    }

    // Sentinel error comparison
    err := findUser("unknown")
    if errors.Is(err, ErrNotFound) {
        fmt.Println("User not found")
    }
}

func findUser(id string) error {
    // Error wrapping with context
    return fmt.Errorf("findUser %s: %w", id, ErrNotFound)
}

%w ile sarmalama, hataları zincirler ve özgün hatayı test etme imkânını korur.

12. panic ve recover ne zaman kullanılmalı?

panic normal akışı keser ve yığını çözer. recover ise paniği bir defer içinde yakalar ve yürütmenin devam etmesini sağlar.

panic_recover.gogo
package main

import "fmt"

func safeOperation() (err error) {
    defer func() {
        if r := recover(); r != nil {
            err = fmt.Errorf("recovered from panic: %v", r)
        }
    }()

    riskyOperation()
    return nil
}

func riskyOperation() {
    // Simulates an operation that can panic
    panic("something went wrong")
}

// Legitimate use case: initialization validation
func MustCompileRegex(pattern string) *Regexp {
    r, err := regexp.Compile(pattern)
    if err != nil {
        panic(err) // Programming error
    }
    return r
}

func main() {
    err := safeOperation()
    if err != nil {
        fmt.Println("Recovered error:", err)
    }
    fmt.Println("Program continues")
}
Altın kural

Panic, yalnızca programlama hataları (ihlal edilen değişmezler) için kullanılır. Beklenen hatalarda (eksik dosya, ağ sorunu) her zaman bir error döndürmek daha güvenlidir.

Yapılar, metotlar ve embedding

13. Değer ve işaretçi receiver'lar arasındaki fark nedir?

Değer receiver'ı struct'ın bir kopyasını alır; işaretçi receiver'ı bir referans alır ve orijinali değiştirebilir.

receivers.gogo
package main

import "fmt"

type Counter struct {
    value int
}

// Value receiver - works on copy
func (c Counter) GetValue() int {
    return c.value
}

// Pointer receiver - modifies original
func (c *Counter) Increment() {
    c.value++
}

// Pointer receiver for large structs (avoids copy)
type LargeStruct struct {
    data [1000]int
}

func (l *LargeStruct) Process() {
    // Avoids copying 8000 bytes
}

func main() {
    c := Counter{value: 0}
    c.Increment() // Go automatically converts
    fmt.Println(c.GetValue()) // 1

    // Careful with interfaces
    var _ fmt.Stringer = &c // OK if method on *Counter
}

Kural: bir metot işaretçi receiver'ı kullanıyorsa, tutarlılık adına o tipteki tüm metotlar işaretçi receiver kullanmalıdır.

14. Go'da embedding nasıl çalışır?

Embedding bir tipi başka bir tipin içine yerleştirir; metot ve alanlarını miras alır. Bu klasik kalıtım değil, kompozisyondur.

embedding.gogo
package main

import "fmt"

type Logger struct {
    prefix string
}

func (l *Logger) Log(msg string) {
    fmt.Printf("[%s] %s\n", l.prefix, msg)
}

// Embedding Logger
type Service struct {
    *Logger // Pointer embedding
    name    string
}

func NewService(name string) *Service {
    return &Service{
        Logger: &Logger{prefix: name},
        name:   name,
    }
}

func main() {
    svc := NewService("API")

    // Promoted method - direct access
    svc.Log("Starting")

    // Explicit access also works
    svc.Logger.Log("Explicit")

    // Promoted field
    fmt.Println(svc.prefix) // "API"
}

Embedding, kalıtımın katılığından kaçınarak esnek kompozisyonlar sağlar.

15. Go'da singleton deseni nasıl uygulanır?

sync paketi, eşzamanlı goroutine'ler arasında bile başlatmanın yalnızca bir kez yapılmasını garanti eden sync.Once'ı sunar.

singleton.gogo
package main

import (
    "fmt"
    "sync"
)

type Database struct {
    connectionString string
}

var (
    instance *Database
    once     sync.Once
)

func GetDatabase() *Database {
    once.Do(func() {
        fmt.Println("Single initialization")
        instance = &Database{
            connectionString: "postgres://...",
        }
    })
    return instance
}

func main() {
    // Concurrent calls - single initialization
    var wg sync.WaitGroup
    for i := 0; i < 10; i++ {
        wg.Add(1)
        go func() {
            defer wg.Done()
            db := GetDatabase()
            fmt.Printf("Instance: %p\n", db)
        }()
    }
    wg.Wait()
}

sync.Once thread-safe'tir ve double-check locking'li bir mutex'ten daha zariftir.

Context ve iptal

16. context paketi ne işe yarar?

context paketi; deadline'ları, iptal sinyallerini ve bir isteğe bağlı değerleri çağrı ağacı boyunca yönetir.

context.gogo
package main

import (
    "context"
    "fmt"
    "time"
)

func main() {
    // Context with timeout
    ctx, cancel := context.WithTimeout(
        context.Background(),
        2*time.Second,
    )
    defer cancel() // Always call cancel

    result := make(chan string, 1)

    go func() {
        // Simulate long operation
        time.Sleep(3 * time.Second)
        result <- "completed"
    }()

    select {
    case res := <-result:
        fmt.Println(res)
    case <-ctx.Done():
        fmt.Println("Timeout:", ctx.Err())
    }
}

// Propagation through functions
func fetchData(ctx context.Context, url string) ([]byte, error) {
    // Early check
    if ctx.Err() != nil {
        return nil, ctx.Err()
    }

    req, err := http.NewRequestWithContext(ctx, "GET", url, nil)
    if err != nil {
        return nil, err
    }

    // HTTP client respects context
    resp, err := http.DefaultClient.Do(req)
    // ...
}

Uzun sürebilecek her fonksiyon ilk parametre olarak context.Context almalıdır.

17. Programın graceful shutdown'ı nasıl yönetilir?

SIGINT ve SIGTERM gibi sistem sinyalleri, temiz bir kapanış için yakalanabilir.

graceful_shutdown.gogo
package main

import (
    "context"
    "fmt"
    "os"
    "os/signal"
    "syscall"
    "time"
)

func main() {
    // Context cancelled on signal
    ctx, stop := signal.NotifyContext(
        context.Background(),
        syscall.SIGINT,
        syscall.SIGTERM,
    )
    defer stop()

    // Start server
    server := startServer()

    // Wait for signal
    <-ctx.Done()
    fmt.Println("\nShutting down...")

    // Timeout for graceful shutdown
    shutdownCtx, cancel := context.WithTimeout(
        context.Background(),
        5*time.Second,
    )
    defer cancel()

    if err := server.Shutdown(shutdownCtx); err != nil {
        fmt.Println("Shutdown error:", err)
    }

    fmt.Println("Shutdown complete")
}

Bu desen, kapanmadan önce aktif bağlantıların düzgün şekilde tamamlanmasını sağlar.

Test ve benchmark

18. Go'da test nasıl yazılır?

Yerleşik testing paketi temel işlevselliği sağlar. Testler *_test.go dosyalarında yer alır.

calculator_test.gogo
package calculator

import "testing"

func TestAdd(t *testing.T) {
    result := Add(2, 3)
    if result != 5 {
        t.Errorf("Add(2, 3) = %d; want 5", result)
    }
}

// Table-driven tests
func TestAddTableDriven(t *testing.T) {
    tests := []struct {
        name     string
        a, b     int
        expected int
    }{
        {"positive", 2, 3, 5},
        {"negative", -1, -1, -2},
        {"mixed", -1, 5, 4},
        {"zero", 0, 0, 0},
    }

    for _, tt := range tests {
        t.Run(tt.name, func(t *testing.T) {
            result := Add(tt.a, tt.b)
            if result != tt.expected {
                t.Errorf("Add(%d, %d) = %d; want %d",
                    tt.a, tt.b, result, tt.expected)
            }
        })
    }
}

Tablo tabanlı testler birden çok senaryoyu denemek için Go'nun deyimsel desenidir.

19. Benchmark nasıl yazılır?

Benchmark'lar testing.B kullanır ve go test -bench ile çalıştırılır.

benchmark_test.gogo
package main

import (
    "strings"
    "testing"
)

func BenchmarkStringConcat(b *testing.B) {
    for i := 0; i < b.N; i++ {
        var s string
        for j := 0; j < 100; j++ {
            s += "a"
        }
    }
}

func BenchmarkStringBuilder(b *testing.B) {
    for i := 0; i < b.N; i++ {
        var sb strings.Builder
        for j := 0; j < 100; j++ {
            sb.WriteString("a")
        }
        _ = sb.String()
    }
}

// Typical results:
// BenchmarkStringConcat-8      50000    28000 ns/op
// BenchmarkStringBuilder-8   1000000     1200 ns/op

Benchmark'lar farklı uygulamalar arasındaki performans farklarını ortaya koyar.

Generics (Go 1.18+)

20. Go'da generics nasıl kullanılır?

Go 1.18 tip parametrelerini tanıttı; tip güvenliğini koruyarak generic kod yazmayı mümkün kıldı.

generics.gogo
package main

import "fmt"

// Generic function
func Map[T, U any](slice []T, fn func(T) U) []U {
    result := make([]U, len(slice))
    for i, v := range slice {
        result[i] = fn(v)
    }
    return result
}

// Custom type constraint
type Number interface {
    int | int64 | float64
}

func Sum[T Number](values []T) T {
    var sum T
    for _, v := range values {
        sum += v
    }
    return sum
}

// Generic type
type Stack[T any] struct {
    items []T
}

func (s *Stack[T]) Push(item T) {
    s.items = append(s.items, item)
}

func (s *Stack[T]) Pop() (T, bool) {
    if len(s.items) == 0 {
        var zero T
        return zero, false
    }
    item := s.items[len(s.items)-1]
    s.items = s.items[:len(s.items)-1]
    return item, true
}

func main() {
    // Usage
    doubled := Map([]int{1, 2, 3}, func(n int) int {
        return n * 2
    })
    fmt.Println(doubled) // [2 4 6]

    fmt.Println(Sum([]int{1, 2, 3, 4, 5})) // 15

    stack := &Stack[string]{}
    stack.Push("hello")
    stack.Push("world")
    val, _ := stack.Pop()
    fmt.Println(val) // "world"
}

Generics, kod tekrarına ya da interface{} kullanmaya olan ihtiyacı ortadan kaldırır.

Modüller ve bağımlılıklar

21. Go modül sistemi nasıl çalışır?

Go modülleri bağımlılıkları semantik versiyonlamayla yönetir. go.mod dosyası modülü ve bağımlılıklarını tanımlar.

go.mod examplego
module github.com/user/myproject

go 1.21

require (
    github.com/gin-gonic/gin v1.9.1
    github.com/lib/pq v1.10.9
)

// Essential commands:
// go mod init github.com/user/project
// go mod tidy        - clean dependencies
// go get package@v1.2.3 - add/update
// go mod vendor      - copy locally
bash
# Updating dependencies
go get -u ./...           # All dependencies
go get -u=patch ./...     # Patches only

go.sum dosyası, bağımlılıkların bütünlüğünü garanti eden kriptografik özet değerlerini içerir.

22. Bir Go projesi nasıl yapılandırılmalı?

Standart yapı, katı kurallar dayatmadan topluluk konvansiyonlarını izler.

text
myproject/
├── cmd/
│   └── api/
│       └── main.go      # Entry point
├── internal/            # Private to module
│   ├── handler/
│   ├── service/
│   └── repository/
├── pkg/                 # Reusable external code
├── go.mod
├── go.sum
└── README.md

internal klasörü özeldir: içeriği başka modüller tarafından import edilemez.

İleri seviye sorular

23. Go'da garbage collector nasıl çalışır?

Go düşük gecikme için optimize edilmiş, eşzamanlı, üç renkli mark-and-sweep garbage collector kullanır.

gc_optimization.gogo
package main

import "runtime"

func main() {
    // GC configuration
    // GOGC=100 (default) - triggers GC when heap doubles

    // Force GC
    runtime.GC()

    // Memory statistics
    var stats runtime.MemStats
    runtime.ReadMemStats(&stats)

    println("Alloc:", stats.Alloc)
    println("NumGC:", stats.NumGC)
    println("PauseTotalNs:", stats.PauseTotalNs)
}

// Optimization techniques
// 1. Reuse allocations with sync.Pool
// 2. Pre-allocate slices with make([]T, 0, cap)
// 3. Avoid repeated string/[]byte conversions
// 4. Use pointers for large structs

GODEBUG=gctrace=1 ortam değişkeni GC izlerini gösterir.

24. Go scheduler'ını açıkla

Go scheduler'ı N goroutine'i M sistem thread'ine eşleyen M:N modelini kullanır; üç varlığı vardır: G (goroutine), M (thread) ve P (mantıksal işlemci).

scheduler.gogo
package main

import (
    "fmt"
    "runtime"
)

func main() {
    // Number of logical processors (P)
    fmt.Println("GOMAXPROCS:", runtime.GOMAXPROCS(0))

    // Number of active goroutines
    fmt.Println("NumGoroutine:", runtime.NumGoroutine())

    // Yield processor to other goroutines
    runtime.Gosched()

    // M:P:G model
    // - G: goroutine (lightweight stack ~2KB)
    // - M: OS thread (machine)
    // - P: logical processor (execution context)
    //
    // Each P has a local queue of Gs
    // Work stealing when queue is empty
}

Scheduler 1.14 sürümünden itibaren preemptif çalışır; bir goroutine'in P'yi tek başına işgal etmesini engeller.

25. Go'da performans nasıl optimize edilir?

Optimizasyon, darboğazları belirlemek için profilleme ile başlar.

profiling.gogo
package main

import (
    "os"
    "runtime/pprof"
)

func main() {
    // CPU profiling
    f, _ := os.Create("cpu.prof")
    pprof.StartCPUProfile(f)
    defer pprof.StopCPUProfile()

    // Code to profile...

    // Memory profiling
    mf, _ := os.Create("mem.prof")
    defer mf.Close()
    pprof.WriteHeapProfile(mf)
}

// Analysis: go tool pprof cpu.prof

// Common optimization techniques:
// 1. Avoid allocations in hot loops
// 2. Use sync.Pool for reusable objects
// 3. Prefer []byte over string for mutations
// 4. Use bufio for I/O
// 5. Batch database operations
Optimizasyon kuralı

Optimize etmeden önce ölçmek gerekir. Profilleme genellikle gerçek darboğazlar hakkında şaşırtıcı sonuçlar ortaya koyar.

Sonuç

Bu 25 soru Go mülakatlarında değerlendirilen temel kavramları kapsar:

Hazırlık kontrol listesi:

  • ✅ Goroutine ve channel'lara hâkimiyet
  • ✅ Örtük arayüzleri kavrama
  • ✅ Deyimsel hata yönetimi
  • ✅ context'in doğru kullanımı
  • ✅ Eşzamanlılık desenleri (mutex, worker pool)
  • ✅ Test ve benchmark
  • ✅ Go 1.18+ generics bilgisi

Go mülakatında başarının anahtarı: sadelik ile performans arasındaki dengeleri kavradığını göstermek ve hangi eşzamanlılık deseninin ne zaman uygulanacağını bilmek.

Pratik yapmaya başla!

Mülakat simülatörleri ve teknik testlerle bilgini test et.

Etiketler

#go
#golang
#interview
#concurrency
#goroutines

Paylaş

İlgili makaleler