codingstuff.io
ExploreTutorialsProblemsCS Subjects
Get Started
ExploreTutorialsProblemsCS Subjects
Get Started
codingstuff.io

Master the art of building software through interactive tutorials, real-world problems, and guided projects.

Pune, Maharashtra, India

codingstuffmail@gmail.com

Product

  • Explore
  • Tutorials
  • Problems
  • CS Subjects

Company

  • About
  • Contact
  • Privacy Policy
  • Terms & Conditions
  • Sitemap

© 2026 codingstuff.io. All rights reserved.

Built with ❤️ for developers everywhere

/
/
All Tutorials
🐹

Go (Golang)

19 / 72 topics
17Concurrency Basics18Goroutines19Channels20Select Statement21Sync Package
Tutorials/Go (Golang)/Channels
🐹Go (Golang)

Channels

Updated 2026-05-15
10 min read

Channels

Introduction

In Go, communication between concurrent processes is primarily handled through channels. A channel is a typed conduit that allows for the transfer of data between goroutines. Channels are used to synchronize and communicate between different parts of your program, ensuring safe access to shared resources.

Channels can be thought of as pipes where one goroutine sends data into the pipe and another reads from it. This communication mechanism is built around Go's concurrency model, making it a fundamental part of writing concurrent programs in Go.

Concept

A channel has two main operations: send and receive. The send operation places a value on the channel, while the receive operation takes a value from the channel. Channels are typed, meaning they can only transfer values of a specific type.

Channels can be created using the make function:

ch := make(chan int)

This creates an unbuffered channel that will block until both the sender and receiver are ready. You can also create buffered channels by specifying a buffer size:

ch := make(chan int, 10)

Buffered channels allow for asynchronous communication, as they store values in a queue up to their capacity.

Examples

Let's explore some practical examples to understand how channels work.

Example 1: Unbuffered Channel

In this example, we'll create an unbuffered channel and use it to send and receive data between two goroutines.

package main

import (
	"fmt"
	"time"
)

func worker(ch chan int) {
	for i := range ch {
		fmt.Printf("Received %d\n", i)
	}
}

func main() {
	ch := make(chan int)

	go worker(ch)

	for i := 0; i < 5; i++ {
		ch <- i
		fmt.Printf("Sent %d\n", i)
		time.Sleep(time.Second)
	}

	close(ch)
}

**Explanation:**

1. We define a `worker` function that reads from the channel and prints the received values.
2. In the `main` function, we create an unbuffered channel `ch`.
3. We start a goroutine that runs the `worker` function, passing it the channel.
4. The main goroutine sends integers to the channel in a loop.
5. After sending all values, we close the channel using `close(ch)` to signal that no more data will be sent.

**Output:**

Sent 0 Received 0 Sent 1 Received 1 Sent 2 Received 2 Sent 3 Received 3 Sent 4 Received 4


### Example 2: Buffered Channel

Now, let's see how buffered channels work. We'll create a buffered channel and observe the behavior when sending and receiving data.

```go
package main

import (
	"fmt"
)

func worker(ch chan int) {
	for i := range ch {
		fmt.Printf("Received %d\n", i)
	}
}

func main() {
	ch := make(chan int, 2)

	go worker(ch)

	for i := 0; i < 5; i++ {
		ch <- i
		fmt.Printf("Sent %d\n", i)
	}

	close(ch)
}

**Explanation:**

1. We create a buffered channel `ch` with a capacity of 2.
2. The main goroutine sends integers to the channel in a loop.
3. Since the channel is buffered, up to two values can be sent without blocking.

**Output:**

Sent 0 Sent 1 Received 0 Received 1 Sent 2 Sent 3 Received 2 Received 3 Sent 4 Received 4


### Example 3: Select Statement

The `select` statement allows a goroutine to wait on multiple communication operations. It blocks until one of the operations is ready.

```go
package main

import (
	"fmt"
	"time"
)

func worker(ch chan int, done chan bool) {
	for i := range ch {
		fmt.Printf("Received %d\n", i)
	}
	done <- true
}

func main() {
	ch := make(chan int)
	done := make(chan bool)

	go worker(ch, done)

	for i := 0; i < 5; i++ {
		select {
		case ch <- i:
			fmt.Printf("Sent %d\n", i)
		case <-time.After(1 * time.Second):
			fmt.Println("Timeout occurred")
		}
		time.Sleep(time.Second)
	}

	close(ch)
	<-done
}

**Explanation:**

1. We define a `worker` function that reads from the channel and sends a signal on the `done` channel when it's done.
2. In the `main` function, we create two channels: `ch` for communication and `done` to signal completion.
3. The main goroutine uses a `select` statement to send values to the channel or handle a timeout.

**Output:**

Sent 0 Received 0 Sent 1 Received 1 Timeout occurred Sent 2 Received 2 Timeout occurred Sent 3 Received 3 Timeout occurred Sent 4 Received 4


## What's Next?

In the next section, we'll explore the `select` statement in more detail. The `select` statement is a powerful tool for handling multiple channels and managing concurrent operations efficiently.

---

By understanding channels and their various use cases, you can write robust and efficient concurrent programs in Go. Channels provide a safe and effective way to communicate between goroutines, making them an essential part of the language's concurrency model.

PreviousGoroutinesNext Select Statement

Recommended Gear

GoroutinesSelect Statement