Пинг-Понг: обмен сообщениями между горутинами

К задачам
Легкая
Concurrency

Условие задачи

Реализуй простую модель обмена сообщениями между двумя горутинами. Одна горутина отправляет "ping", вторая отвечает "pong" — и так по очереди N раз. Каждое сообщение должно выводиться в stdout. Взаимодействие должно происходить через каналы без использования sleep или shared переменных.

package main

import (
    "fmt"
)

func ping(pingCh chan<- string, pongCh <-chan string, n int) {
    // TODO: отправляй "ping" и жди "pong"
}

func pong(pingCh <-chan string, pongCh chan<- string) {
    // TODO: жди "ping" и отвечай "pong"
}

func main() {
    pingCh := make(chan string)
    pongCh := make(chan string)
    n := 10

    go ping(pingCh, pongCh, n)
    go pong(pingCh, pongCh)

    // TODO: дождись завершения
}
package main

import (
    "fmt"
)

func ping(pingCh chan<- string, pongCh <-chan string, n int) {
    // TODO: отправляй "ping" и жди "pong"
}

func pong(pingCh <-chan string, pongCh chan<- string) {
    // TODO: жди "ping" и отвечай "pong"
}

func main() {
    pingCh := make(chan string)
    pongCh := make(chan string)
    n := 10

    go ping(pingCh, pongCh, n)
    go pong(pingCh, pongCh)

    // TODO: дождись завершения
}

Подсказка

- Используй каналы как способ синхронизации. - Используй цикл с n итерациями внутри ping. - Не забудь завершить программу корректно — можно использовать sync.WaitGroup или просто вызвать os.Exit(0) в конце main (в простом варианте).

Решение

Горутины ping и pong взаимодействуют через два канала. Ping отправляет "ping", ждёт "pong". Pong ждёт "ping", отвечает "pong". Всё это происходит синхронно.

package main

import (
    "fmt"
)

func ping(pingCh chan<- string, pongCh <-chan string, n int) {
    for i := 0; i < n; i++ {
        pingCh <- "ping"
        msg := <-pongCh
        fmt.Println(msg)
    }
    close(pingCh)
}

func pong(pingCh <-chan string, pongCh chan<- string) {
    for msg := range pingCh {
        fmt.Println(msg)
        pongCh <- "pong"
    }
    close(pongCh)
}

func main() {
    pingCh := make(chan string)
    pongCh := make(chan string)
    n := 10

    go ping(pingCh, pongCh, n)
    go pong(pingCh, pongCh)

    for range pongCh {
        // ничего не делаем — просто ждём завершения
    }
}
package main

import (
    "fmt"
)

func ping(pingCh chan<- string, pongCh <-chan string, n int) {
    for i := 0; i < n; i++ {
        pingCh <- "ping"
        msg := <-pongCh
        fmt.Println(msg)
    }
    close(pingCh)
}

func pong(pingCh <-chan string, pongCh chan<- string) {
    for msg := range pingCh {
        fmt.Println(msg)
        pongCh <- "pong"
    }
    close(pongCh)
}

func main() {
    pingCh := make(chan string)
    pongCh := make(chan string)
    n := 10

    go ping(pingCh, pongCh, n)
    go pong(pingCh, pongCh)

    for range pongCh {
        // ничего не делаем — просто ждём завершения
    }
}