tgoop.com/dev_easy_notes/30
Last Update:
🙈 Сегодня поговорим про проблему Visibility. Чтобы понять суть проблемы разберем один синтетический пример.
Все программы, которые мы пишем, используют как минимум несколько потоков. Один отвечает за отображение другие за походы в сеть, в файловую систему и много чего еще. Даже когда вы пишете код на js и кажется будто поток всегда один, на самом деле их несколько просто за вас эту работу делает браузер.
Вернемся к проблеме, у нас несколько потоков и есть переменная с которой эти потоки работают. Эта переменная может изменятся из нескольких потоков. Небольшой кусок кода на kotlin:
fun main(){
val threadList = mutableList<Thread>()
var number = 0
repeat(100){
threadList+=thread {
number++
}
}
thread.forEach { it.join()}
print(number)
}
В коде мы запускаем 100 потоков, каждый из потоков увеличивает значение переменной number на 1. Затем мы ждем завершения всех потоков и выводим значение переменной.
❓Вопрос что будет в поле number? Правильный ответ вообще хз. Может быть 100, а может и 98 и 101 можете попробовать сами🙃
Почему так проиходит, почему иногда программа глючит? Чтобы это понять придется погрузится в то, как устроенны процессоры. 💻
Почти все процессоры, даже мобильные имеют несколько ядер, это нужно потому как повышать герцы мы больше не можем и приходится их ускорять путем паррелизации задач.
Пока одно ядро показывает вам видос на YouTube другое ядро в это время ищет вирусы, третье что-то качает с сети и т.п.
У каждого ядра есть кеши, L1..L4. Каждый кеш имеет свой размер и свою скорость записи/чтения. L1 супер быстрое чтение/запись и очень маленький размер ~ 32 Кб. L4 более медленная чтение/запись, но размер уже по больше ~ 16 МБ байт. Естественно размеры зависят он конкретного процессора.
Эти кеши нужны чтобы процессор не ходил в оперативу каждый раз. Это еще одна оптимизация для ускорения, так как ходить в кеш гораздо быстрее, ведь он находится в самом процессоре.
Теперь возвращаемся к нашему примеру, у нас создается 100 потоков, и предположим у системы 4 ядра, значит скорее всего параллельно будут работать 4 потока.
🙌И теперь следите за руками, когда процессор работает с переменной number, это значение он сначала кладет в кеш L1, затем спустя какое-то время это значение из кеша попадает в оперативную память. Увеличение значения переменной просиходит в 3 шага, получить переменную, увеличить на один и записать переменную.
Допустим поток X взял переменную пока её значение было 1, затем он увеличил её до 2 и записал это значение. Это значение сначало записалось в кеш, и только спустя какое-то время оно попадет в оперативную память.
В это время другой поток Y тоже хочет проделать аналогичную операцию. Он также идет в оперативную память, получает значение 1, так как поток X работает на другом ядре и еще не записал значение в оперативную память. Поток Y получает получает значение 1 увеличивает его на 1 и записывает 2, аналогично потоку X.
В итоге должно было получиться 3, но получилось 2 из-за того, что потоки не видят того, что делают другие потоки, или видят значение но с опозданием. 🕰
Это сильное упращение того, что проиcходит в реальности, однако суть таже. Это фундаментальная проблема Visibility в многопоточности. О том как решается эта проблема поговорим в отдельном посте.
BY Dev Easy Notes

Share with your friend now:
tgoop.com/dev_easy_notes/30