Основы JavaScript: управление DOM элементами (часть 2)



Книга Основы JavaScript: управление DOM элементами (часть 2)

Горутина — это эффективный и легковесный механизм многопоточного выполнения, популярный среди разработчиков Go. С помощью семантики горутин программисты добиваются эффективного выполнения параллельных процессов в программе. Впрочем, следует помнить о подводных камнях, чтобы избежать незапланированных побочных эффектов. 


Программа


Логика программы проста: есть набор функций определенного типа, который нужно перебрать и выполнить. Каждая из функций независима, поэтому удобно использовать индивидуальные горутины. Код имеет следующий вид:


import (
"fmt"
"sync"
)

func main() {
ConcurrentFunctions(func1, func2)
}

func ConcurrentFunctions(fns ...func()) {
var wg sync.WaitGroup
for _, fn := range fns {
wg.Add(1)
go func() {
fn()
wg.Done()
}()
}

wg.Wait()
}

func func1() {
fmt.Println("I am function func1")
}

func func2() {
fmt.Println("I am function func2")
}

“ConcurrentFunctions” — это функция с переменным количеством аргументов, которая принимает на вход любое число функций, перебирает и реализует их. Реализация каждой функции происходит за счёт отдельной горутины. Согласно логике, вывод должен был быть “I am function func1” и “I am function func2”, но это не так.


I am function func2
I am function func2

Ошибка


Загвоздка кроется в этой части кода:


for _, fn := range fns {
wg.Add(1)
go func() {
fn()
wg.Done()
}()
}

Каждая итерация цикла создавала анонимную функцию замыкания с горутиной, использующей ту же переменную “fn”, что и родительский цикл. Горутины выполняются асинхронно, поэтому для каждой из них в момент использования актуальна переменная “fn”. В большинстве случаев внешний цикл завершался до реализации какой-либо горутины, поэтому “fn” указывает на “func2”. Таким образом, обе горутины замыкаются на func2.


Решение


Поскольку причиной ошибки стала переменная “fn”, проблему может решить изменение следующей секции кода:


for _, fn := range fns {
wg.Add(1)
go func(f func()) {
f()
wg.Done()
}(fn)
}

Вместо обращения к переменной “fn” напрямую, механизм замыкания горутины принимает функцию в качестве параметра, при этом копируя её для каждой из итераций горутин.


С этим небольшим изменением выходные данные приняли следующий вид:


I am function func2
I am function func1

410   0  

Comments

    Ничего не найдено.