Forwarded from Denis Sexy IT 🤖
А вот что она умеет генерировать уже сейчас; а помните были такие люди – «художники»? 🌚
👍1😱1
Data race (или просто гонка)
Представим, что есть некий код, который запускает 2 параллельных потока, внутри каждого в цикле, например 1 млн раз, происходит одна операция:
а = а + 1
где а - одна и та же переменная (например глобальная).
Ожидаемый результат - a == 2 млн
Фактический результат - a < 2 млн. Точное значение всегда разное.
Так происходит потому что a = a + 1 для процессора на самом деле является не одной операцией, а тремя:
1. Взять из оперативки значение в переменной а и поместить ее в регистр процессора
2. Прибавить к этому значению 1 (результат суммирования лежит в регистре)
3. Сохранить результат из регистра в оперативную память
И при параллельной работе с этой переменной порядок этих операцией не гарантируется. То есть нет гарантии в каком порядке потоки ОС будут выполнять эти операции. Отсюда и возникает состояние гонки.
Пример.
Допустим есть 2 потока ОС. Работу начинает первый. a = 0
1 поток. Выполнил 1. (в регистре: 0, в оперативке а=0)
1 поток. Выполнил 2. (в регистре: 1, в оперативке а=0)
Переключение контекста (начал работу второй поток)
2 поток. Выполнил 1. (в регистре: 0, в оперативке а=0)
2 поток. Выполнил 2. (в регистре: 1, в оперативке а=0)
2 поток. Выполнил 3. (в регистре: 1, в оперативке а=1)
Переключение контекста (начал работу первый поток)
1 поток. Выполнил 3 (в регистре: 1, в оперативке а=1)
Таким образом, после того, как 2 потока сделали a = a + 1 в переменной лежит не 2, а 1.
Чтобы избежать состояния гонки надо запретить двум потокам одновременный доступ к общему участку памяти (Участок кода, где это происходит называется критическая секция).
Сделать это можно с помощью мьтекса (лок): до операции над критической секцией делаем Lock(), после операции над критической секцией делаем Unlock().
Суть этого в том, что пока один поток "держит" лок, то другой поток при попытке сделать Lock() блокируется и ждет, пока другой поток не сделает Unlock(). В результате этого все 3 операции для инкремента переменной всегда происходят атомарно и проблемы возникнуть не может.
Пример кода:
https://go.dev/play/p/BGzDCig5dGQ
Представим, что есть некий код, который запускает 2 параллельных потока, внутри каждого в цикле, например 1 млн раз, происходит одна операция:
а = а + 1
где а - одна и та же переменная (например глобальная).
Ожидаемый результат - a == 2 млн
Фактический результат - a < 2 млн. Точное значение всегда разное.
Так происходит потому что a = a + 1 для процессора на самом деле является не одной операцией, а тремя:
1. Взять из оперативки значение в переменной а и поместить ее в регистр процессора
2. Прибавить к этому значению 1 (результат суммирования лежит в регистре)
3. Сохранить результат из регистра в оперативную память
И при параллельной работе с этой переменной порядок этих операцией не гарантируется. То есть нет гарантии в каком порядке потоки ОС будут выполнять эти операции. Отсюда и возникает состояние гонки.
Пример.
Допустим есть 2 потока ОС. Работу начинает первый. a = 0
1 поток. Выполнил 1. (в регистре: 0, в оперативке а=0)
1 поток. Выполнил 2. (в регистре: 1, в оперативке а=0)
Переключение контекста (начал работу второй поток)
2 поток. Выполнил 1. (в регистре: 0, в оперативке а=0)
2 поток. Выполнил 2. (в регистре: 1, в оперативке а=0)
2 поток. Выполнил 3. (в регистре: 1, в оперативке а=1)
Переключение контекста (начал работу первый поток)
1 поток. Выполнил 3 (в регистре: 1, в оперативке а=1)
Таким образом, после того, как 2 потока сделали a = a + 1 в переменной лежит не 2, а 1.
Чтобы избежать состояния гонки надо запретить двум потокам одновременный доступ к общему участку памяти (Участок кода, где это происходит называется критическая секция).
Сделать это можно с помощью мьтекса (лок): до операции над критической секцией делаем Lock(), после операции над критической секцией делаем Unlock().
Суть этого в том, что пока один поток "держит" лок, то другой поток при попытке сделать Lock() блокируется и ждет, пока другой поток не сделает Unlock(). В результате этого все 3 операции для инкремента переменной всегда происходят атомарно и проблемы возникнуть не может.
Пример кода:
https://go.dev/play/p/BGzDCig5dGQ
package main
import (
"fmt"
"sync"
)
var a = 0
func main() {
var wg sync.WaitGroup
wg.Add(1)
go increment(&wg)
wg.Add(1)
go increment(&wg)
wg.Wait()
fmt.Println(a)
}
func increment(wg *sync.WaitGroup) {
defer wg.Done()
for i := 0; i < 1e6; i++ {
a = a + 1
}
}
👍2🔥1
Прямо сейчас произошло на работе
https://www.youtube.com/watch?v=eYBwY6zKSNk
https://www.youtube.com/watch?v=eYBwY6zKSNk
YouTube
Фитиль "Порожняк" (1969) смотреть онлайн
Смотрите на iPad: https://itunes.apple.com/ru/app/rvision-tv/id810243002
Подписывайтесь: http://www.youtube.com/subscription_center?add_user=FitilOfficial
Кинопортал RVision.tv - http://rvision.tv
Вступайте в группу: http://vk.com/rvision
Порожняк (1969)…
Подписывайтесь: http://www.youtube.com/subscription_center?add_user=FitilOfficial
Кинопортал RVision.tv - http://rvision.tv
Вступайте в группу: http://vk.com/rvision
Порожняк (1969)…
😁2
У DeliveryClub есть крутая Pro подписка, которая делает доставку бесплатной во многих местах.
Стоит 100р в месяц (первый вообще 1р). С учетом того, что сама доставка без подписки 129р за 1 раз, то это очень выгодно.
Стоит 100р в месяц (первый вообще 1р). С учетом того, что сама доставка без подписки 129р за 1 раз, то это очень выгодно.
❤1