Go Lang/Study

[GoLang] 반복문에서 고루틴 돌릴 때 주의점

DSeung 2024. 1. 19. 03:47

주의

반복문에서 고루틴을 돌리면 신기하게 결과물이 나올 때가 있습니다.

아래 코드를 실행했을 때의 결과는 무엇일까요?

import (
	"fmt"
	"sync"
)

func main() {
	var wg sync.WaitGroup
	for _, text := range []string{"a", "b", "c"} {
		wg.Add(1)
		go func() {
			defer wg.Done()
			fmt.Println(text)
		}()
	}
	wg.Wait()
}

 

만약 a, b, c가 랜덤으로 출력 것이라 생각하신다면 틀렸습니다

결과는 아래와 같습니다.

c
c
c

 

왜 이런 일이

이유는 루프문이 고루틴보다 먼저 끝나서 고루틴에서 사용할 수 있도록 메모리를 힙으로 옮겼기 때문입니다.

즉 for문이 먼저 끝나서 text의 값은 마지막 c를 가리키기에 이런 일이 발생한 것입니다.

 

참고로

※ 힙(Heap) : 동적으로 메모리를 할당한 부분, 사용자가 직접 할당 및 해제를 해야 함, 일반적으로 프로그램 실행 중의 생기고 제거됨

※ 스택(Stack) : 함수 내의 지역 변수 및 매개변수를 저장하며 LIFO으로 동작하며 해당 함수가 종료 시 제거함

해결법

해결법은 간단합니다, 고루틴이 실수로 할당이 해제되어야 하는 변수에 접근하지 못하도록 메모리에 값이 고정된 변수를 접근하게 수정하면 됩니다.

 

해당 기능은 이미 지원하고 있습니다.

아래 코드로 수정해 봅시다.

import (
	"fmt"
	"sync"
)

func main() {
	var wg sync.WaitGroup
	for _, text := range []string{"a", "b", "c"} {
		wg.Add(1)
        // 고루틴 함수에서 매개변수를 받도록 바꿈
		go func(text string) {
			defer wg.Done()
			fmt.Println(text)
		}(text)
	}
	wg.Wait()
}

위 코드처럼 간단하게 매개변수로 받게 수정함으로써 해결할 수 있습니다.

 

고루틴은 이것 외에도 주의해야 하는 점이 여러 개 있습니다.

아래는 동시성 환경에서 발생하는 문제점입니다, 보시고 도움이 되었으면 좋겠습니다.

 

https://seung.tistory.com/entry/GoLang-%EB%8D%B0%EB%93%9C%EB%9D%BD-%EB%9D%BC%EC%9D%B4%EB%B8%8C%EB%9D%BD-%EA%B8%B0%EC%95%84%EC%83%81%ED%83%9C-%EC%9D%B4%ED%95%B4%ED%95%98%EA%B8%B0-Deadlock-Livelock-Starvation?category=1161608

 

[GoLang] 데드락, 라이브락, 기아상태 이해하기 (Deadlock, Livelock, Starvation)

개요이번 포스팅은 Golang을 할 때 가장 큰 장점으로 꼽히는 부분인 동시성(고루틴)과 크게 관련된 내용입니다.동시성 프로그래밍은 사실 쉽지 않습니다.  동시에 실행된다는 개념 때문에 프로그

seung.tistory.com

 

 

위 글의 제목처럼 동시성 문제를 해결하기 위해서는 공유 메모리에 대해서

동기화된 접근만 하거나 고의 CSP( Communicating Sequential Processes ) 기본요소를 사용하면 됩니다.

  • Goroutine
  • Channel 
  • Select
  • Mutex
  • WaitGroup

 

반응형