> 백엔드 개발 > Golang > Go 언어의 자원 경쟁 문제에 대해 이야기하는 기사

Go 언어의 자원 경쟁 문제에 대해 이야기하는 기사

青灯夜游
풀어 주다: 2023-02-17 18:18:46
앞으로
3255명이 탐색했습니다.

Go 언어의 자원 경쟁 문제에 대해 이야기하는 기사

우리 모두는 동시 프로그래밍에서 스레드 안전성이 매우 중요하다는 것을 알고 있습니다. 다음으로 스레드가 안전하지 않은 상황을 재현하는 시나리오를 가정하고 Go에서

scenario

을 해결하는 방법에 대해 이야기하겠습니다. 이제 1부터 100까지 팩토리얼을 찾아 결과를 a에 입력해야 합니다. map

1! = 1 = 1
2! = 1 * 2 = 2
3! = 1 * 2 * 3 = 6
4! = 1 * 2 * 3 * 4 = 24
5! = 1 * 2 * 3 * 4 * 5 = 120
...
{
    1: 1
    2: 2
    3: 6
    4: 24
    5: 120
    ...
}
로그인 후 복사

var factorialMap = make(map[int]int)

func Factorial(n int) {
    result := 1
    for i := 1; i <= n; i++ {
        result *= i
    }
    factorialMap[n] = result
}

func main() {
    for i := 1; i < 10; i++ {
        Factorial(i)
    }
    for k, v := range factorialMap {
        fmt.Printf("%d 的阶乘是%d\n", k, v)
    }
}
로그인 후 복사

Go 언어의 자원 경쟁 문제에 대해 이야기하는 기사코드 구현 위의 코드 실행 결과는 실제로 문제가 없습니다. 왜 순서가 뒤바뀌는 상황이 발생하는 걸까요? 이것은 Go 언어의 지도이기 때문에 실제로는 순서가 맞지 않습니다. 우리가 이해한 바에 따르면 선입선출이지만 죄송하지만 Golang의 지도는 이와 같지 않습니다. 위의 실행에는 문제가 없습니다. 주의 깊은 학생들은 이 버전의 코드가 동시성을 사용하지 않는다는 것을 발견했을 것입니다. 자,

동시성 구현

var factorialMap = make(map[int]int)

func Factorial(n int) {
    result := 1
    for i := 1; i <= n; i++ {
        result *= i
    }
    factorialMap[n] = result
}

func main() {
    for i := 1; i < 10; i++ {
        go Factorial(i)
    }
    for k, v := range factorialMap {
        fmt.Printf("%d 的阶乘是%d\n", k, v)
    }
}
로그인 후 복사

Go 언어의 자원 경쟁 문제에 대해 이야기하는 기사을 계속 개선해 보겠습니다. 동시 버전에서는 계승 함수를 계산하기 위해 호출 앞에 go而已。不要小看这个go를 추가하는 것을 볼 수 있는데, 이는 너무 멀리 떨어져 있습니다. 물론 모두가 알고 있는 사실입니다. 이것은 go 언어에서 함수를 여는 것입니다. 코루틴의 키워드를 사용하세요.

실행 결과 콘솔에 아무것도 출력되지 않는 이유는 메인 코루틴과 서브 코루틴의 실행 관계 때문입니다. 이해를 돕기 위해 그림을 그려보겠습니다.

Go 언어의 자원 경쟁 문제에 대해 이야기하는 기사위 그림을 보면 알 수 있습니다. 메인 코루틴의 실행 시간은 짧고(비교적 짧은 것으로 표시), 서브 코루틴의 실행 시간은 상대적으로 길다(비교적 긴 것으로 표시). 서브 코루틴은 현재 메인 코루틴에 상대적이라는 점을 기억해야 합니다. 메인 코루틴이 더 이상 존재하지 않으면 서브 코루틴도 존재하지 않게 됩니다. 따라서 메인 코루틴 프로세스가 실행되었기 때문에 위의 코드는 아무것도 출력하지 않습니다. 그런데 하위 코루틴이 완료되지 않은 경우, factorialMap에 아무것도 없을 수 있나요?

메인 및 기타 하위 코루틴factorialMap中能有东西吗?

主等子

这就引出我们第一个问题,主协程如何等待子协程执行完再退出程序。我们现在用一个最简单,最容易想到的做法

var factorialMap = make(map[int]int)

func Factorial(n int) {
    result := 1
    for i := 1; i <= n; i++ {
        result *= i
    }
    factorialMap[n] = result
}

func main() {
    for i := 1; i < 100; i++ {
        go Factorial(i)
    }
    time.Sleep(time.Second * 3)
    for k, v := range factorialMap {
        fmt.Printf("%d 的阶乘是%d\n", k, v)
    }
}
로그인 후 복사

Go 언어의 자원 경쟁 문제에 대해 이야기하는 기사当并发数比较小的时候,这个问题可能不会出现,一旦并发数变大,问题就立马出现了

图中的执行结果是并发map写入错误为什么会出现这个问题,我们假设100个人往一个篮子里放水果,很容易。但是100个人从一个篮子里拿水果,那就会出问题,首先,篮子里的水果不一定够100个,其二每个人都想先拿,必然会引起争抢。

问题一优化

针对上面的问题,我们引入全局锁的概念。这就有点像我们上厕所,100个人都想上厕所,但厕所只有1个,谁先抢到了谁先上,并且这个人还有给厕所上锁,防止其他人进来

Go 언어의 자원 경쟁 문제에 대해 이야기하는 기사

var factorialMap = make(map[int]int)
var lock sync.Mutex

func Factorial(n int) {
    result := 1
    for i := 1; i <= n; i++ {
            result *= i
    }
    // defer 不好理解
    // defer func(){
    // 	lock.Unlock() // 执行完解锁
    // }()
    lock.Lock() // 执行时上锁
    factorialMap[n] = result
    lock.Unlock() // 执行后解锁
}

func main() {
    for i := 1; i < 100; i++ {
        go Factorial(i)
    }
    time.Sleep(time.Second * 3)
    for k, v := range factorialMap {
        fmt.Printf("%d 的阶乘是%d\n", k, v)
    }
}
로그인 후 복사

Go 언어의 자원 경쟁 문제에 대해 이야기하는 기사执行结果有0可能是数据类型存不下了导致的,这个大家不用关心

Go 언어의 자원 경쟁 문제에 대해 이야기하는 기사这样我们就解决了资源竞争的问题了。但其实还有一个问题,就是我们在主协程中还是必须手动等待,这要非常不好,那如果子协程3秒内解决不了怎么办?

问题二优化

这个问题是我们不想在主协程中手动等待子协程,换句话说是我们不想直接在代码中写明要等待多长时间

这里我们就引入了WaitGroup

이것은 프로그램을 종료하기 전에 메인 코루틴이 하위 코루틴의 실행이 완료될 때까지 어떻게 기다리는지에 대한 첫 번째 질문으로 이어집니다. 우리는 이제 가장 간단하고 쉬운 생각 방법을 사용하고 있습니다WaitGroup

var factorialMap = make(map[int]int)
var lock sync.Mutex
var wg sync.WaitGroup

func Factorial(n int) {
    result := 1
    for i := 1; i <= n; i++ {
        result *= i
    }
    lock.Lock() // 执行时上锁
    factorialMap[n] = result
    lock.Unlock() // 执行后解锁
    wg.Done()
}

func main() {
    for i := 1; i < 100; i++ {
        wg.Add(1)
        go Factorial(i)
    }
    wg.Wait()
    for k, v := range factorialMap {
        fmt.Printf("%d 的阶乘是%d\n", k, v)
    }
}
로그인 후 복사
 image .png동시 횟수가 상대적으로 적을 때는 이 문제가 발생하지 않을 수 있습니다. 동시 횟수가 커지면 문제가 즉시 나타납니다. 사진의 실행 결과는

Concurrent 맵입니다. writing error 왜 이런 문제가 발생할까요? 100명이 과일을 바구니에 담았다고 가정해 보겠습니다. 하지만 100명이 바구니에서 과일을 가져간다면 문제가 생길 것입니다. 첫째, 바구니에 과일이 충분하지 않을 수 있습니다. 둘째, 모두가 먼저 가져가고 싶어하므로 필연적으로 경쟁이 발생합니다.

문제 1 최적화🎜🎜🎜위의 문제를 고려하여 전역 잠금 개념을 소개합니다. 화장실에 가고 싶어하는 사람이 100명인데 화장실이 하나밖에 없어서 먼저 잡는 사람이 먼저 가고, 이 사람도 다른 사람이 들어오지 못하도록 화장실을 잠그는 것과 비슷합니다🎜 🎜Go 언어의 자원 경쟁 문제에 대해 이야기하는 기사🎜rrreee🎜실행 결과는 0, 이는 데이터 유형을 저장할 수 없기 때문에 발생할 수 있습니다. 네, 걱정할 필요가 없습니다🎜🎜Go 언어의 자원 경쟁 문제에 대해 이야기하는 기사이런 방식으로 자원 경쟁 문제를 해결합니다. 하지만 실제로는 또 다른 문제가 있습니다. 즉, 여전히 메인 코루틴에서 수동으로 기다려야 하는데, 이는 하위 코루틴이 3초 이내에 해결되지 않으면 어떻게 될까요? 🎜

🎜문제 2 최적화🎜🎜🎜이 문제는 메인 코루틴에서 수동으로 서브 코루틴을 기다리고 싶지 않다는 것입니다. 대기하는 코드를 직접 작성하고 싶습니다. 얼마나 오래🎜🎜여기서🎜🎜rrreee🎜WaitGroup의 내부 원칙을 소개했습니다. 직접 확인하실 수 있습니다. 지금은 들어가지 않겠습니다. 요약하면 🎜는 코루틴이 열릴 때마다 바스켓에 식별자가 추가됩니다(Add 함수). 코루틴이 실행될 때마다 바스켓에서 식별자가 뺍니다(Done 함수). 바구니가 조회되고 비어 있으면 코루틴이 실행되었다는 의미입니다. (대기 기능)🎜🎜[추천 학습: 🎜go 비디오 튜토리얼🎜]🎜

위 내용은 Go 언어의 자원 경쟁 문제에 대해 이야기하는 기사의 상세 내용입니다. 자세한 내용은 PHP 중국어 웹사이트의 기타 관련 기사를 참조하세요!

관련 라벨:
원천:juejin.cn
본 웹사이트의 성명
본 글의 내용은 네티즌들의 자발적인 기여로 작성되었으며, 저작권은 원저작자에게 있습니다. 본 사이트는 이에 상응하는 법적 책임을 지지 않습니다. 표절이나 침해가 의심되는 콘텐츠를 발견한 경우 admin@php.cn으로 문의하세요.
인기 튜토리얼
더>
최신 다운로드
더>
웹 효과
웹사이트 소스 코드
웹사이트 자료
프론트엔드 템플릿