• Что бы вступить в ряды "Принятый кодер" Вам нужно:
    Написать 10 полезных сообщений или тем и Получить 10 симпатий.
    Для того кто не хочет терять время,может пожертвовать средства для поддержки сервеса, и вступить в ряды VIP на месяц, дополнительная информация в лс.

  • Пользаватели которые будут спамить, уходят в бан без предупреждения. Спам сообщения определяется администрацией и модератором.

  • Гость, Что бы Вы хотели увидеть на нашем Форуме? Изложить свои идеи и пожелания по улучшению форума Вы можете поделиться с нами здесь. ----> Перейдите сюда
  • Все пользователи не прошедшие проверку электронной почты будут заблокированы. Все вопросы с разблокировкой обращайтесь по адресу электронной почте : info@guardianelinks.com . Не пришло сообщение о проверке или о сбросе также сообщите нам.

Go (11) - Channels & Concurrency

Lomanu4 Оффлайн

Lomanu4

Команда форума
Администратор
Регистрация
1 Мар 2015
Сообщения
1,481
Баллы
155
Concurrency VS Synchronization

Synchronous code


When code executes line by line in order, one thing at a time is called synchronous. It is simple, but sometimes might not be very efficient.

Concurrency


func main() {
// block 1
x := 10
x++
fmt.Printf("x = %d", x)

// block 2
y := 20
y--
fmt.Printf("y = %d", y)
}

Check the code blocks in the above example. As you can see, the code lines in block 1 should execute in order. The code lines in block 2 should also execute line by line. But blocks 1 and 2 have no dependency on each other. So, we can run them separately on two CPU cores. This is called running in Parallel. It increases efficiency.

In Golang, it is easy to write concurrent code.

Go routine


func main() {
// some code
go funcName()

// rest of the code
}

In the above example, you can see go funcName(). It tells that the funcName() function runs in parallel with the rest of the code in the main function.
So all you need to do is use the go keyword to instruct it to run in concurrent mode. We have a special name here for concurrent functions: go routine. In the above example, funcName() is a go routine.

We can't expect return values from a go routine like we get from a regular function.
Now, you might wonder what the use of these go routines is if they can't even return a value. That is why we have channels.

Channels


Channels are used to communicate between goroutines. They are a type-safe and thread-safe queue.
One or more goroutines can put data into a channel, and one or more other goroutines read that data from the channel.

Syntax to make a channel,


ch := make(chan int)

Above, initialize a channel of type int.

You can put data into channels using the syntax below.


ch <- 10

The <- is called the channel operator. The arrowhead shows the data flow direction.

Use the below syntax to receive data from a channel.


val := <- ch

It removes the value from the channel and saves it to the val variable.

Both sending and receiving data operations are blocking operations. If a value is sent to a channel but there is no other goroutine to receive the data, the code will stop and wait. The same happens during the reading. When a goroutine is expecting data from a channel, but no one is writing data to it, then the code is blocked there.
A token is a unary value. Most of the time, empty structs are used as tokens. What is passed through the channel is not a concern in this scenario. <-ch syntax is used to block and wait until something is sent to a channel.

Buffered Channels


When making a channel, we can make it buffered by providing a buffer length as the second argument.


ch := make(chan int, 100)

When the buffer is full, sending to the channel gets blocked. Likewise, when the buffer is empty, the receiving from the channel is blocked.

Closing channels


Channels should always be closed from the sending side. It says that this channel is closed, there's nothing more to read from it. The syntax is given below.


ch := make(chan int)
// code lines ...
close(ch)

Therefore, on the reading side, we have to check whether a channel is closed.


v, ok := <-ch

In the above example, the ok is a boolean variable. Its value is true if the channel is open. Else, ok is false.

If you send a value to a closed channel, that go routine will panic.
Closing a channel is not necessary. Unused open channels are garbage collected.

Range


The range can be used on channels as well. The example below receives values over the channel until it is closed. When the channel is closed, the loop exists.


for item := range ch {
// item is the next value received from the ch
}
Select


When there is a single goroutine listening to multiple channels, we might need to process data in order per channel. In this case, we can use the select statement to switch between channels.


select {
case i, ok := <- chInst:
if !ok {
return
}
fmt.Print(i)
case s, ok := chString:
if !ok {
return
}
fmt.Print(i)
}
Read-only channels


When you want to make a channel read-only, you should cast it from chan to <-chan type.


func readCh(ch <-chan int) {
// ch is a read-only channel in this function
}
Write-only channels


To make a channel write-only, you should cast it from chan to chan<- type.


func readCh(ch chan<- int) {
// ch is a write-only channel in this function
}
Read-only and write-only channels concept is useful in identifying which functions use the channel for reading and which use it for writing.
Few points to remember:

  • A send to a nil channel blocks the code forever
  • A receive from a nil channel blocks forever
  • A send to a closed channel panics
  • A receive from a closed channel returns the zero value


Пожалуйста Авторизируйтесь или Зарегистрируйтесь для просмотра скрытого текста.

 
Вверх Снизу