프로그래밍

동시성 프로그래밍 관점에서 Golang vs Java

hayz 2024. 4. 1. 00:28

Golang과 Java 각각의 프로그래밍 언어를 동시성 프로그래밍의 관점에서 차이점을 정리해본다. 

 

Golang 을 처음 공부 하다 보면  '고루틴(goroutine)' 이라는 용어를 많이 접할 수 있다. 이 고루틴은 쓰레드 처럼 동시성 처리를 위해 사용된다. 그러면 이 고루틴이 다른 언어들의 동시성 처리 방법과 어떤점이 다른지, 그 중에 Java 와 비교해서 차이점을 알아본다. 

 

우선 기존의 Java 에서 사용하는 쓰레드(Thread) 란?

말 그대로 우리가 기존에 알고 있던 프로세스와 쓰레드 개념에서 나온 쓰레드 라고 생각하면 된다.  하나의 프로세스 안에 여러 쓰레드가 존재할 수 있으며, 이 쓰레드를 이용해 여러 작업을 동시에 처리 하고, 각 쓰레드 간의 데이터 교환도 가능하다. Java 에서는 이런 쓰레드를 Jvm 위에서 관리될 수 있도록 도와준다.  

[1] process vs thread example

 

 

그러면 Golang 에서 사용하는 고루틴이란?

고루틴은, 쓰레드와 비슷하게 동시성 작업을 위한 목적으로 존재하지만, 실행되는 단위에서 차이가 있다. 위에서 설명 한 것 처럼 Java 는 쓰레드와 OS 커널에서의 쓰레드가 1:1 로 매핑 되는 것에 반면에, Golang 에서는 고루틴과 OS 커널 쓰레드가 N:M 로 매핑이 된다. 즉, 여러개의 쓰레드 위에 여러 개의 고루틴을 돌릴 수 있다. 

이렇게 되면 Java 에서 동시성 처리를 위해 쓰레드를 사용하는 것보다 훨씬 더 많은 양의 동시성 처리 루틴을 생성하고 실행할 수 있게 된다. 그래서 고루틴을 경량 쓰레드 라고 부르기도 한다. 

 

고루틴이 쓰레드 위에서 경량화 되어서 동작하는 방법

그러면 실제로, 고루틴이 쓰레드 보다 경량화 되어 있다고 볼 수 있을까? 

고루틴이 동작하는 방식은 간단하게 보면, 여러개의 쓰레드가 있고, 그 위에서 경량화된 동시성 객체들이 존재한다고 볼 수 있다. 그리고 이러한 객체들을 고루틴에서 관리하고 있어서 하나의 쓰레드에 여러개의 고루틴이 동작할 수 있게 된다. 각 고루틴은 스택의 2KB 정도만을 할당 받고, 고루틴 사용량에 따라 동적으로 증가 되기 때문에 기본적으로 MB 단위의 쓰레드보다 메모리 효율성이 좋다. 

 

[2] goroutine with thread example

 

Golang 에서 많은 양의 고루틴을 띄워도 괜찮을까? 얼마나 띄울수 있을까? 

Golang 문서에서 보면, 수십만개의 고루틴을 동일한 주소 공간에 생성할 수 있다고 나와 있다. 예를 들면, 약 4GB 메모리를 가진 머신 위에서 100만개의 고루틴을 동작시킬 수 있는 것이다. 고루틴의 동작 특성에 따라 차이는 있겠지만.. 사실상 프로그램을 실행 하며 몇만개의 동시성 요소를 실행하는 일은 흔치 않기 때문에 사용에 제한이 없다고 봐도 될것 같다. 

 

 

 

 

Reference

[1] https://www.baeldung.com/cs/process-vs-thread

[2] https://medium.com/@genchilu/javas-thread-model-and-golang-goroutine-f1325ca2df0c

[3] https://go.dev/doc/faq#goroutines