Расскажите о своем опыте работы с конкурентностью (concurrency) в Go.

Ответ

Да, имею большой опыт. Модель конкурентности в Go — одна из ключевых особенностей языка. Она построена на горутинах (goroutines) и каналах (channels), что соответствует философии: "Не обменивайтесь данными, разделяя память; вместо этого, разделяйте память, обмениваясь данными".

Ключевые инструменты:

  • Горутины: Это легковесные потоки, управляемые средой выполнения Go (Go runtime). Их создание очень дешево по сравнению с системными потоками, что позволяет запускать сотни тысяч горутин одновременно.
  • Каналы: Это типизированные "трубы", через которые горутины могут безопасно обмениваться данными, избегая состояния гонки.
  • select: Оператор, который позволяет горутине ждать нескольких операций с каналами одновременно, подобно switch, но для каналов.

Пример: Worker Pool

Этот паттерн отлично демонстрирует совместную работу горутин и каналов для параллельной обработки задач.

package main

import (
    "fmt"
    "time"
)

// worker получает задания из канала `jobs` и отправляет результат в `results`.
func worker(id int, jobs <-chan int, results chan<- int) {
    for j := range jobs {
        fmt.Printf("worker %d started job %dn", id, j)
        time.Sleep(time.Second) // Имитация работы
        fmt.Printf("worker %d finished job %dn", id, j)
        results <- j * 2
    }
}

func main() {
    const numJobs = 5
    jobs := make(chan int, numJobs)
    results := make(chan int, numJobs)

    // Запускаем 3 воркера. Они будут заблокированы, пока в канал `jobs` не поступят данные.
    for w := 1; w <= 3; w++ {
        go worker(w, jobs, results)
    }

    // Отправляем 5 заданий в канал `jobs` и затем закрываем его.
    for j := 1; j <= numJobs; j++ {
        jobs <- j
    }
    close(jobs)

    // Собираем результаты. Цикл завершится, когда все 5 результатов будут получены.
    for a := 1; a <= numJobs; a++ {
        <-results
    }
    fmt.Println("All jobs are done.")
}

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