SoFunction
Updated on 2025-03-05

Introduction to the use of GoLang channel

Stop signal

There are quite a lot of scenarios for channel to stop signals. Often, it is to close a channel or send an element to the channel so that the party receiving the channel knows this information and then does some other operations.

Task timing

Combined with timer, there are generally two ways to play: implement timeout control and implement regular execution of a certain task.

Sometimes, you need to perform an operation, but don't want it to take too long, and the previous timer can do it:

select {
	case <-(100 * ):
	case <-:
		return false
}

After waiting for 100 ms, if the data has not been read out or has been closed, it will be terminated directly. This is an example from the etcd source code, and such writing can be seen everywhere.

It is also relatively simple to execute a task regularly:

func worker() {
	ticker := (1 * )
	for {
		select {
		case &lt;- ticker:
			// Execute timing tasks			("Execute 1s timed tasks")
		}
	}
}

Perform a timed task every 1 second.

Decoupling the producer and consumer

When the service starts, n workers are started, as a work coroutine pool, these coroutines work in onefor {}In an infinite loop, consume work tasks from a channel and execute:

func main() {
	taskCh := make(chan int, 100)
	go worker(taskCh)
    // Stop mission	for i := 0; i &lt; 10; i++ {
		taskCh &lt;- i
	}
    // Wait for 1 hour	select {
	case &lt;-():
	}
}
func worker(taskCh &lt;-chan int) {
	const N = 5
	// Start 5 work coroutines	for i := 0; i &lt; N; i++ {
		go func(id int) {
			for {
				task := &lt;- taskCh
				("finish task: %d by worker %d\n", task, id)
				()
			}
		}(i)
	}
}

5 working coroutines are constantly taking tasks from the work queue, and the producer only needs to send tasks to the channel, decoupling the producer and the consumer.

finish task: 1 by worker 4
finish task: 2 by worker 2
finish task: 4 by worker 3
finish task: 3 by worker 1
finish task: 0 by worker 0
finish task: 6 by worker 0
finish task: 8 by worker 3
finish task: 9 by worker 1
finish task: 7 by worker 4
finish task: 5 by worker 2

Control the number of concurrency

Sometimes hundreds of tasks are required to be performed regularly, such as performing some offline calculation tasks based on cities every day. However, the number of concurrency cannot be too high, because the task execution process relies on some resources from third parties and has limits on the request rate. At this time, the concurrency number can be controlled through channel.

The following example comes from "Go Advanced Programming":

var limit = make(chan int, 3)
func main() {
    // …………
    for _, w := range work {
        go func() {
            limit <- 1
            w()
            <-limit
        }()
    }
    // …………
}

Build a buffered channel with a capacity of 3. Then iterate through the task list, and each task starts a goroutine to complete. The action of truly executing tasks and accessing third parties is completed in w(). Before executing w(), you must first get the "license" from limit. Only after obtaining the license can you execute w(). After executing the task, you must return the "license". This allows you to control the number of goroutines running simultaneously.

here,limit <- 1Put it inside and not outside of func for the reason:

If it is on the outer layer, it is the number of goroutines in the system, which may block the for loop and affect the business logic.

limit is actually not related to logic, it is just performance tuning, and the semantics of the inner and outer layers are different.

Another thing to note is that if w() panic occurs, the "license" may not be returned, so defer is needed to ensure it.

This is the end of this article about the introduction to the use of GoLang channel. For more related Go channel content, please search for my previous articles or continue browsing the related articles below. I hope everyone will support me in the future!