Channels are tools to allow safe communication between concurrent code. They allow concurrent code to communicate by sending messages. Channels can be thought of as pipelines for safely sending and receiving messages between different coroutines – no matter the thread in which they are running.
Let's look at some examples of how channels can be used in real-life, non-trivial scenarios. This will help you to understand how useful channels can be when implementing tasks that require many coroutines to do collaborative work. As an exercise, try to think of a way to solve the problems listed here without channels.