본문 바로가기
프로그래밍/golang

concurrency in go(2)

by 나도한강뷰 2023. 1. 3.

3장 go 동시성 구성 요소

고루틴

  • 가장 기본적인 단위(main도 하나의 고루틴이다)
  • 고루틴은 os스레드가 아니고, 그린스레드도 아니고, coroutine이라고 불리는 더 높은 추상화이다.
    • hw 스레드: 물리 cpu를 가상화하여서 2개의 코어로 만드는것. hyper-threading기능이라고 생각하면 됨
    • os 스레드(native 스레드): 일반적으로 우리가 생각하는 core의 메모리를 공유하는 프로세스, cpu스케쥴링의 단위
    • 그린 스레드: 유저스레드 to os스레드가 many to one으로 연결되는 형태
    • 코루틴: 동시에 실행되는 서브루틴으로 비선점적인 루틴을 의미한다.
  • 고루틴은 go 런타임과 긴밀하게 통합되어 있어서, 잘 효율적으로 실행됨
  • m:n 스케줄러를 구현한것으로 m개의 그린 슬레드를 n개의 os스레드에 매핑하는 것. 그후 고루틴은 스레드에 스케줄링된다.
  • fork-join모델을 따른다.
    • 단순한게 time sleep을 하는건 레이스 컨디션을 만들뿐이다.
    • 고루틴은 자신이 생성된 곳과 동일한 주소 공간에서 실행된다.고루틴들은 순차적으로 실행된다는 보장이 없으며, 그것을 위해서 여러가지 고려를 하여서 코드를 작성해야된다.
    • 고루틴이 실행되기전 이미 for loop는 종료되었고, 그 메모리 주소만 공유되고 있었기때문에 고루틴이 메모리에 접근할 수 있도록 메모리를 힙으로 옮겼고, c만 출력되게 된다.
  • 가비지컬렉터는 버려진 고루틴을 회수하기위해서 어떠한 것도 하지않는다.
  • 고루틴은 엄청 싸다. 70만개에 메모리 2GB
  • 컨텍스스위칭도 엄청 싸다. 소프트웨어 스위칭이기때문에 저장할것을 선택할 수 있기 때문에.
var wg sync.WaitGroup
for _, salutation := range[]string{"a","b","c"}
	wg.Add(1)
    go func (){ 
    	defer wg.Done
        fmt.Println(salutation) }() 
    wg.Wait()
    
 결과값 c c c

sync 패키지(기존 메모리 공유 방식 지원)

  • waitGroup
    • 동시에 수행된 연산의 결과를 신경 쓰지 않는경우
    • 결과를 수집할 다른 방법이 있는 경우 동시에 수행될 연산 집합을 기다릴때
    • 동시에 실행해도 안전한 카운터(add(+), done(-), wait)
  • mutex와 rwmutex
    • mutex는 상호 배제 mutual exclusion, 임계 영역을 보호
    • 규칙을 만들어 메모리를 공유
    • (lock, unlock) lock을하고 defer unlock을 호출
    • 임계 영역은 프로그램의 병목지점이다.
    • rwmutex(read write), 좀더 메모리를 제어 할 수 있는 것
    • 쓰기일때는 잠금, 읽기만 있으면 몇개든 ok
  • cond
    • 고루틴들이 대기하거나, 어떤 이벤트의 발생을 알리는 집결 지점
    • 고루틴에서 신호를 기다리기
    • 가장쉬운 방법은 무한루프를 사용
    • 신호를 받을때까지 슬립하고 자신의 상태를 확인하는 방식
    • (L.lock, L.unlock, signal, broadcast)
    • signal은 fifo로 가장 오래기다른 고루틴에게 신호전달
    • groadcast는 대기중인 모든 고루틴에게 동시에 신호전달
  • once
    • once의 do 메소드는 once자체를 단 1번마 실행하게 만든다.
    • do의 호출함수 기준이 아닌 do의 호출 횟수가 중요하다.
  • pool
    • 데이터베이스 연결같이 비용이 많이 드는 것의 생성수를 제한해 고정된 수만 생성하도록 하는 기능
    • (get put)
    • get을 통해서 사용가능한 인스턴수 수를 1개 감소시간다.
    • put을 통해서 사용가능한 인스턴수 수를 1개 증가시킨다.
    • go에는 가비지컬렉터가 있으므로, 인스턴스화된 객체는 자동으로 정리된다.
    • 높은 처리가 필요한 네트워크 서버를 작성하는 경우 필요하다.

채널

  • go동기화의 기본 요소
  • 메모리 접근을 동기화
  • 고루틴 간에 정보를 전달할 때 가장 적합
  • 변수의 마지막은 stream으로
  • 채널 선언 및 인스턴트화 2스텝
  • 데이터 형을 선언, 주소값 전달
  • := make(chan int)와 같은 형태로 한번에 선언 가능
  • value, ok := <-stringStream(value는 전달된 값 ok는 open channel은 true, close channel은 false)
    • 두번째 반환값은 channel의 close여부를 판별하기위함, close일때 계속 defaul값이들어온다.
    • 채널을 닫는것또한 여러개의 수신 채널에 동시에 신호를 보내는 방법 중 하나이다.
  • 버퍼링된 채널(버퍼에 쌓아놓는다.) 다쌓이면 송신채널은 대기하게 된다.
    • 버퍼링 채널은 성급한 최적화가 될 수 있고, 데드락의 원인이 될 수 있다.
  • 채널의 소유권을 할당하는걸 가장 먼저 해야된다.
    • 채널 인스턴트화/ 다른 고루틴에게 소유권을 넘긴다/ 채널을 닫는다/ 캡슐화한다
  • 채널 소비자
    • 언제 채널 닫히는지 아는것(두번째 리턴값)/ 대기가 발생하면 책임있게 처리하는 것

select 구문

  • 채널을 하나로 묶는 방식
    • 채널 읽기와 쓰기를 동시에 고려
    • 준비된 채널이 없을 경우 select문 전체가 중단 대기된다.
    • case 구문의 집합에 대한 균일한 의사 무작위 선택, 완전 랜덤
    • 동시에 case에 입력이 들어가면? 그럼 모두 랜덤 선택case에대해서 순차적으로 테스트되지않으며, 조건이 충족되지않는다고 다음으로 넘어가지 않는다.
    • 모든 채널이 차단되어 대기하는 경우 대비해 default절을 허용한다.
    • select{} 무한대기
var c <- chan int
select {
	case <-c:
	case<-time.After(1*time.Second):
    	fmt.print("timed out")
    }
    
결과: 1초만 기다리고 종료됨

'프로그래밍 > golang' 카테고리의 다른 글

concurrency in go(4)  (0) 2023.01.06
concurrency in go(3)  (0) 2023.01.04
concurrency in go(1)  (0) 2022.12.31
google go style guide 공부  (0) 2022.12.12
golang 팀내 테스트 코드 작성  (0) 2022.11.20