This is the 5th day of my participation in the More text challenge. More text Challenge this article has participated in the weekend learning plan, click the link to view the details: juejin.cn/post/696572…

If ❤️ my article is helpful, welcome to like, follow. This is the biggest encouragement for me to continue my technical creation.

Last time we used the Sync implementation to support goroutine concurrency. Continuing with the download file example, use channels for concurrency

package main

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

func main(a)  {
	// ============== channel ==============
	startTime2 := time.Now()

	testChannel()

	endTime2 := time.Now()
	fmt.Printf("======> Done! use time: %f",(endTime2.Sub(startTime2).Seconds()))
	fmt.Println()
}

// Using channel channels, messages can be passed between coroutines. Wait for the concurrent coroutine to return a message.
var ch = make(chan string.10) // Create a cache channel of size 10
func testChannel(a) {
	for i := 0; i < 3; i++ {
		go downloadV2("a.com/" + string(i+'0'))}for i := 0; i < 3; i++ {
		msg := <-ch // Wait for channel to return a message.
		fmt.Println("finish", msg)
	}
}

// ================= tool V =================

func downloadV2(url string) {
	fmt.Println("start to download", url)
	time.Sleep(time.Second)
	ch <- url // Send the URL to the channel
}
Copy the code

Channel

A channel is the communication mechanism between goroutines. Each channel has a special type, the type that Channels can send data to. A channel that can send data of type int is written as chan int.

Golang advocates a communication approach instead of shared memory. When a resource needs to be shared between goroutines, channels provide a conduit between goroutines and a mechanism to ensure that data is exchanged synchronously.

When declaring channels, you need to specify the type of data to be shared. Values or Pointers of built-in, named, structural, and reference types can be shared through channels.

Declaring channel types

To declare a channel, specify the type of the shared data. The syntax for declaring a channel is as follows: var Channel variable Chan Channel type

  • Channel type:Intra-channel transmissionThe type of the data
  • The null value of type chan is nilmakeBefore use.

Create channels

= make(chan datatype)

Data type: The type of data being transferred in the channel. Channel instance: Channel handle created by make.

Here’s an example:

ch1 := make(chan int)                 // Create a channel of type integer
ch2 := make(chan interface{})         // Create an empty interface type channel that can store any format

type Equip struct{ /* Some fields */ }
ch2 := make(chan *Equip)             // Create a pass of type *Equip pointer
Copy the code

Use channels to send data

Once a channel is created, it can be used for send and receive operations.

The format in which the channel sends data

The channel is sent using the special operator <-, which sends data through the channel in the format: channel variable <- value

  • Channel variables: Channel instances created by make.
  • Value: can be a variable, constant, expression, function return value, etc.The type of the valueMust be connected toCh channelElement type ofconsistent.

After creating a channel with make, you can use <- to send data to the channel as follows:

// Create an empty interface channel
ch := make(chan interface{})
// Put 0 into the channel
ch <- 0
// Put the Hello string into the channel
ch <- "hello"
Copy the code

Sending continues to block until data is received

When sending data to a channel, if the receiver never receives it, the send operation continues to block. When the Go program runs, it intelligently detects statements that will never be sent and prompts it as follows:

package main
func main(a) {
    // Create an integer channel
    ch := make(chan int)
    // Try to send 0 over the channel
    ch <- 0
}
Copy the code

Run code, error:

fatal error: all goroutines are asleep – deadlock!

The runtime found that all goroutines (including main) were waiting for a Goroutine. That is, all channels in goroutine have no send and receive code.

Use channels to receive data

Channel receiver also uses the <- operator. Channel receiver has the following features:

  • Channels are sent and received between two different Goroutines.

Because the data sender continues to block when the channel’s data is not processed by the receiver, the channel’s reception must take place in another Goroutine.

  • Reception continues to block until the sender sends the data.

If there is no sender in the channel to send data when the receiver receives, the receiver will also block until the sender sends data.

  • Receive one element at a time.

A channel can only receive one data element at a time.

The data receiving of a channel can be written in the following four ways:

Block receiving data

When the blocking mode receives data, it uses the receiving variable as the lvalue of the <- operator in the format data := <-ch

Execution of this statement blocks until data is received and assigned to the data variable.

Non-blocking data is received

When data is received from a channel in non-blocking mode, the statement does not block in the following format: data, OK := <-ch

  • Data: indicates the received data. When no data is received, data is the zero value of the channel type.
  • Ok: indicates whether data is received.

The non-blocking channel receive method can cause higher CPU usage and is therefore used very rarely. If you want to implement receive timeout detection, you can do it in conjunction with SELECT and counting channels, as described below.

Receives arbitrary data and ignores the received data

After blocking the data received, the data returned from the channel is ignored in the following format: <-ch

Execution of this statement blocks until data is received, which is ignored. This approach is really just a concurrent synchronization between goroutines by blocking traffic between channels.

To use a channel for concurrent synchronization, see the following example:

package main
import (
    "fmt"
)
func main(a) {
    // Build a channel
    ch := make(chan int)
    // Start a concurrent anonymous function
    go func(a) {
        fmt.Println("start goroutine")
        // Notify main's Goroutine via a channel
        ch <- 0
        fmt.Println("exit goroutine")
    }()
    fmt.Println("wait goroutine")
    // Wait for the anonymous Goroutine
    <-ch
    fmt.Println("all done")}// Output is as follows:
// wait goroutine
// start goroutine
// exit goroutine
// all done
Copy the code