在Golang应用程序中使用非缓冲通道一次传输一条信息

179 阅读2分钟

这个例子使用 Golang 的非缓冲通道。未缓冲的通道一次只包含一个值。因此,它们被称为阻塞通道,并像这样创建:make(chan TYPE) 。为了演示使用方法,我们将每2秒一个城市的问候。然而,如果在问候中出现5秒的延迟,我们将使应用程序超时。请阅读内联评论以获得详细解释。

例子1

如果你把睡眠时间从2秒增加到5/+秒以下,应用程序将超时而不打印任何东西。在select 语句中没有一个default 块,所以它将阻塞,直到通过我们的通道收到一个消息,然后继续阻塞,或者遇到超时情况自动退出。在这种情况下,main 函数是接收者welcome 函数是发送者

package main

import (
	"fmt"
	"os"
	"time"
)

func main() {
	// List of cities.
	cities := []string{"London", "Istanbul", "Berlin", "Madrid"}

	// Create unbuffered channel.
	ch := make(chan string)

	// Pass channel and cities to welcome function and run it as goroutine.
	go welcome(ch, cities)

	// Indefinitely wait for the channel to return something.
	for {
		select {
		// If something was received through the channel, print it.
		case msg := <-ch:
			fmt.Println(msg)
		// If nothing was received through the channel for 5 seconds, timeout.
		case <-time.After(5 * time.Second):
			fmt.Println("timeout")
			os.Exit(0)
		}
	}
}

// welcome accepts write-only channel and list of cities.
func welcome(ch chan<- string, cities []string) {
	// Loop through the cities.
	for _, city := range cities {
		// Sleep 2 seconds before writing to the channel below.
		time.Sleep(1 * time.Second)

		// Write (send) greeting message to the channel.
		ch <- fmt.Sprintf("Welcome to %s", city)
	}
}

输出

$ go run -race cmd/client/main.go
Welcome to London
Welcome to Istanbul
Welcome to Berlin
Welcome to Madrid
timeout

例2

这是一个更简单的版本,因为我们没有使用超时。相反,我们明确地关闭通道:

package main

import (
	"fmt"
	"time"
)

func main() {
	// List of cities.
	cities := []string{"London", "Istanbul", "Berlin", "Madrid"}

	// Create unbuffered channel.
	ch := make(chan string)

	// Pass channel and cities to welcome function and run it as goroutine.
	go welcome(ch, cities)

	// Indefinitely wait for the channel to return something.
	for msg := range ch {
		fmt.Println(msg)
	}

	fmt.Println("done")
}

// welcome accepts write-only channel and list of cities.
func welcome(ch chan<- string, cities []string) {
	// Loop through the cities.
	for _, city := range cities {
		// Sleep 2 seconds before writing to the channel below.
		time.Sleep(1 * time.Second)

		// Write (send) greeting message to the channel.
		ch <- fmt.Sprintf("Welcome to %s", city)
	}

	// Close the channel so that range loop knows when to exit.
	close(ch)
}
Welcome to London
Welcome to Istanbul
Welcome to Berlin
Welcome to Madrid
done

例三

在这个例子中,我们是一个一个地传递城市,而不是全部:

package main

import (
	"fmt"
	"time"
)

func main() {
	// List of cities.
	cities := []string{"London", "Istanbul", "Berlin", "Madrid"}

	// Create unbuffered channel.
	ch := make(chan string)
	
	for _, city := range cities {
		// Pass channel and city to welcome function and run it as goroutine.
		go welcome(ch, city)

		// Indefinitely wait for the channel to return something.
		for msg := range ch {
			fmt.Println(msg)

			break
		}
	}

	fmt.Println("done")
}

// welcome accepts write-only channel and city.
func welcome(ch chan<- string, city string) {
	// Sleep 2 seconds before writing to the channel below.
	time.Sleep(1 * time.Second)

	// Write (send) greeting message to the channel.
	ch <- fmt.Sprintf("Welcome to %s", city)
}
Welcome to London
Welcome to Istanbul
Welcome to Berlin
Welcome to Madrid
done