Java: 컴파일된 바이트코드가 JVM(Java Virtual Machine)에서 실행됩니다. 컴파일 단계에서 오류를 잡아낼 수 있어 상대적으로 실행 시 안정성이 높습니다.
-> Java의 실행 단계 : 개발자는 Java 언어로 소스 코드를 작성합니다. -> 바이트코드라는 Java Compiler(javac)를 통해 변환하여 .class 파일로 저장 (오직 JVM만이 이 코드를 읽고 실행할 수 있음) -> 각 운영체제마다 맞춰진 JVM을 통해 바이트코드를 받아서 실행하여 기계어로 변환하여 프로그램을 실행
=> 이를 통해 한 번 컴파일된 Java 바이트코드는 어는 운영체제든 JVM만 설치되어 있다면 실행될 수 있어 플랫폼 독립성을 가질 수 있다.
Python : 인터프리터 방식으로, 코드가 한 줄씩 실행됩니다. 즉석에서 코드를 실행할 수 있어 테스트나 간단한 스크립트 작성에 유리합니다.
-> 한줄씩 실행되기 때문에 문제를 빠르게 수정하고 찾아내는데 용이하지만 인터프리터는 실행할 때마다 코드를 해석하기 때문에, 동일한 코드라도 반복 실행 시 해석 작업이 중복되어 실행 속도가 느립니다.
-> C 기반 라이브러리 사용으로 최적화를 시킬 수 있다.
-> JIT 컴파일러(Just-In-Time Compiler)는 코드를 실행 시에 기계어로 변환해 빠르게 처리하기에 빠르게 실행할 수 있다.(ex - pypy) : 기본적인 인터프리터는 코드를 직접 기계어로 번역하지 않고, 인터프리터가 코드의 각 명령어를 해석하여 그에 맞는 기계어 명령을 생성하고 즉시 실행하지만 JIT는 프로그램이 실행 중일 때 반복적으로 사용하는 코드 블록을 미리 기계어로 변환하여 캐시에 올려두기 때문에 즉시 해석되는 부분이 줄기 때문에 성능이 향상된다.
-> Cython을 통해 Python코드에 C언어의 성능을 결합할 수 있게 해주는 확장 라이브러리로 속도를 빠르게 처리할 수 있다.
-> 기본적으로 Python은 멀티프로세싱을 지원한다. 하지만 Python 인터프리터가 동시에 하나의 스레드만 실행하도록 제한하는 잠금장치인 GIL이 있기에 병렬 처리가 제한된다. 이 GIL은 Python의 메모리 관리와 객체 모델의 안전성 보장을 위해 사용되는 안전장치이다.
: GIL이 작동하는 방식 : Python 프로그램이 멀티스레딩으로 실행될 때, GIL은 특정 시점에 한 스레드만 Python 코드를 실행하도록 한다. 스레드가 실행을 완료하거나 일정한 시간이 지나면 GIL이 다른 스레드로 넘어가면서 실행을 교대로 처리하게 된다. 이 때문에 CPU 연산이 많은 작업을 병렬로 처리하기 위해 멀티스레딩을 사용할 때 GIL이 병목현상을 일으킬 수 있습니다.
-> multiprocessing 라이브러리를 사용하면 여러 프로세스를 병렬로 실행하여 CPU 자원을 효율적으로 사용할 수 있다. 이는 GIL(Global Interpreter Lock) 문제를 우회하는 방법으로, CPU 연산을 병렬로 처리하여 연산이 많은 작업에 적합. 하지만 그래도 프로세스 간 데이터를 공유하기 어렵고 메모리 사용량이 높은 등의 비용이 추가로 발생
-> GPU를 통해 대규모 계산을 가속화할 수 있음(GPU 가속을 지원하는 Python라이브러리들이 있음) 그렇기에 대규모 데이터 분석, 딥러닝, 머신러닝 등에서 사용
: GPU는 Graphics Processing Unit의 약자로 원래는 그래픽 처리를 위해 설계된 프로세서 이지만 주로 그래픽 카드에 내장되어 있으며, 화면에 이미지를 빠르게 렌더링하거나 복잡한 3D 그래픽 연산을 수행하는데 특화되어 있습니다. GPU는 수많은 코어로 이루어져 있어서 대량의 데이터 연산을 병렬로 처리하는데 매우 효율적입니다.
: CUDA는 NVIDIA가 개발한 GPU 프로그래밍을 위한 플랫폼 및 API입니다. CUDA를 사용하면 개발자가 GPU에서 실행되는 프로그램을 작성하여 병렬 처리를 효과적으로 수행할 수 있습니다. Python, C, C++ 언어에서 CUDA를 이용해 GPU의 연산 능력을 활용할 수 있습니다. 딥러닝 모델 학습 시 수많은 행렬 연산이 필요한데 이 때 CPU가 아닌 GPU에서 수행하도록 CUDA를 통해 프로그래밍 하면 작업을 훨씬 빠르게 완료할 수 있습니다.
Java 백엔드 개발자로서 멀티스레드와 메모리 관리 등을 실습해볼 수 있는 간단한 프로젝트들이 있습니다. 이러한 연습을 통해 실제로 동시성과 병렬성을 다루는 감각을 기를 수 있을 거예요. 몇 가지 추천하는 실습 아이디어는 다음과 같습니다.
ServerSocket을 사용해 간단한 TCP 서버를 만들고, 각 클라이언트 요청에 대해 새로운 스레드를 생성해 응답을 처리합니다.ExecutorService) 사용.ForkJoinPool과 같은 병렬 처리 도구 사용법, 데이터 동기화와 안전성.@Async를 사용해 비동기적으로 여러 작업을 동시에 처리하는 API 엔드포인트를 구축합니다.이렇게 간단한 프로젝트들을 통해 멀티스레드, 메모리 관리, 가비지 컬렉션에 대한 이해를 실습으로 넓힐 수 있을 거예요.