GO의 병행성, 병렬성

설탕유령·2023년 1월 30일
0

Go 언어는 병행성(Concureency, 동시성)을 제공함
병행성병렬성(Paraleelism)은 서로 다른 개념

병행성

  • 동시 처리의 논리적인 개념(구조, 설계)
  • 단일(또는 멀티) 코어에서 스레드 여러 개가 시간을 쪼개어 순차적(시분할)으로 실행
  • 사람이 느끼기에 동시로 느껴짐

병렬성

  • 동시 처리의 물리적인 개념(실행)
  • 작업을 여러 CPU에 나눠서 동시에 처리하는 상태
  • 실제로도 실행이 동시적인 시점을 가짐

동시성(병행성)은 두 개 이상의 작업이 동시에 진행되도록 프로그램을 구성하는 것과 관련됨
병렬성은 두 개 이상의 작업이 동시에 실행되도록 함
병렬 처리에는 둘 이상의 프로세서나 스레드가 필요하지만 동시성은 필요 없음

다음은 동시성의 예제

2개의 Task를 Processor에서는 번갈아 가면서 진행함
두 Task 사이에 전환 시간은 매우 짧음으로 인간이 느끼기에 동시에 실행된다고 느껴짐

다음은 병행성에 예제

여러개의 프로세스를 통해 여러개의 문제를 동시에 실행함(물리적, 시간적으로 동시)
병렬성을 사용해 복잡한 한개의 문제를 작은 조각으로 나눠 동시에 실행해 전체 문제가 해결되는 속도를 높일 수 있음
만약 단 1개의 프로세서만 존재한다면, 순차적으로 처리됨

Go의 동시성

Go에서 동시성을 활용하기 위해 고루틴을 사용함
고루틴은 자체 스레드 또는 프로세스에서 실행되지 않음
Go 런타임은 고루틴을 계속 실행하기 위해 필요에 따라 스레드에 고루틴을 동적으로 다중화

다음은 동시성을 테스트하기 위한 예제

package main
import (
  "fmt"
  "time"
)
func numSearch(targetVal int) {
  searchList := []int{1, 2, 3, 4, 5, 6, 7, 8, 9, 10}
  time.Sleep((time.Duration(targetVal) * 100) * time.Millisecond)
  for _, num := range searchList {
    if num == targetVal {
      fmt.Printf("I found the targetVal: %d \n", targetVal)
      return
    }
  }
  fmt.Println("targetVal not found :(")
}
func main() {
  numSearch(10)
  numSearch(1)
  // time.Sleep(10000 * time.Millisecond) 
  fmt.Println("The program has finished executing.")
}

// 실행 결과
I found the targetVal: 10
I found the targetVal: 1
The program has finished executing.

마지막 두번쨰 줄 time.Sleep을 주석 상태로 실행하면 코드가 순차적으로 실행됨을 확인 가능
numSearch 함수를 확인하면 time.Duration에 넘겨지는 targetVal이 높을 수록 나중에 실행됨을 알 수 있음
즉, 매개변수를 1을 전달할 때보다 10을 전달할 때 실행하는 데 더 오래걸림
하지만 함수 호출이 순차적으로 실행 되기 때문에 두 번째 호출은 첫 번째 호출이 완료될 떄까지 시작되지 않음

만약 numSearch 함수를 고루틴으로 바꾸면 다른 결과가 나옴

package main
import (
  "fmt"
  "time"
)
func numSearch(targetVal int) {
  searchList := []int{1, 2, 3, 4, 5, 6, 7, 8, 9, 10}
  time.Sleep((time.Duration(targetVal) * 100) * time.Millisecond)
  for _, num := range searchList {
    if num == targetVal {
      fmt.Printf("I found the targetVal: %d \n", targetVal)
      return
    }
  }
  fmt.Println("targetVal not found :(")
}
func main() {
  go numSearch(10) // 고루틴으로 변경
  go numSearch(1) // 고루틴으로 변경
  time.Sleep(10000 * time.Millisecond) // 주석 해제
  fmt.Println("The program has finished executing.")
}

// 실행 결과
I found the targetVal: 1
I found the targetVal: 10
The program has finished executing.

결과를 보면 두번째로 호출된 numSearch(1)의 결과가 먼저 출력되었는데 고루틴을 통해 첫 번째 호출인 numSearch(10)의 결과를 기다리지 않았기 때문

위는 간단한 예제로 동시성의 이점을 살릴 수 있는 상황중 하나를 예시로 설명하고자 함
사용자 요청을 처리하기 위한 서버가 여러개로 분산화 되어있는 상황
순차적으로 처리하는 경우, 1번 서버, 2번 서버에 요청을 보내고 대기하면서 해당 서버가 요청이 처리 가능한 판별
순차적 방식은 효율적인 선택을 보장하지 못함
처리 가능한 느린 2번 서버와 빠른 5번 서버가 존재하는 경우, 먼저 응답을 받은 2번 서버를 선택

동기적으로 처리하는 경우 만약 10개의 서버가 존재한다면, 10개 서버에 동시에 요청을 보내고 대기,
이후 응답이 돌아온 서버 중 사용자 요청을 처리 가능하면서 가장 빨리 응답이 되돌아온 서버를 선택하고, 기존 미해결 프로세스(다른 서버에 요청을 보내고 대기하는 등..)를 종료 가능

동시성은 작업을 수행하기 위해 병렬성을 사용할 수 있지만 병렬성이 동시성의 궁극적인 목표는 아님
동시성은 독립적인 여러 작업을 한 번에 수행하도록 설계하는 쪽에 무게를 둔 개념
병렬성은 하나의 작업을 설계된 대로 분할해서 동시에 수행하는 쪽에 무게를 둔 개념

Concurrency is about dealing with lots of things at once.
Parallelism is about doing lots of things at once

동시성은 여러 가지 일을 한 번에 처리 하는 것
병렬성은 여러 가지 일을 한 번에 수행 하는 것

  • Go Concurrency Patterns, Rob Pike -
profile
달콤살벌

0개의 댓글