(출처: https://parang0309.tistory.com/30)
이 중에서 서비스 개발 현업에서 사용되고 있는 개념이나 기술에는 Thread & Lock, Functional, Actor(개념만), Data Parallelism, Channel 등이 있음
Lambda Architecture는 big data 분야에서 널리 쓰이지만 프로그래밍 레벨로 들어온 것이 아니라서(아키텍쳐 레벨임) 여기서 다루지 않음
Concurrency | Parallelism | |
---|---|---|
한글 용어 | 동시성 | 병렬성 |
범위 | 가상적/개념적 | 물리적 |
관점 | 설계 | 구현/하드웨어 |
의미 | 겹치는 시간 동안에 여러 태스크가 동시에 실행되는 것 | 여러 태스크가 다중 컴퓨팅 자원을 가지고 같은 시간에 실행되는 것 |
(출처: https://freecontent.manning.com/concurrency-vs-parallelism/) |
(출처: https://freecontent.manning.com/concurrency-vs-parallelism/) |
|
구어체로 표현하자면 | 한 번에 많은 일을 | 많은 일을 동시에 |
단일 코어에서 | 동시성을 가질 수 있음 | 병렬성을 가질 수 없음 |
public class SimpleThreadExample {
public static void main(String[] args) {
Thread thread1 = new Thread(() -> System.out.println("Hello from Thread 1"));
Thread thread2 = new Thread(() -> System.out.println("Hello from Thread 2"));
thread1.start();
thread2.start();
try {
thread1.join(); // 첫 번째 쓰레드가 완료될 때까지 대기
thread2.join(); // 두 번째 쓰레드가 완료될 때까지 대기
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
Hello from Thread 1
Hello from Thread 2
(순서 뒤바뀔 수 있음)
#include <stdio.h>
#include <pthread.h>
void* printHello(void* id) {
printf("Hello from Thread %ld\n", (long)id);
return NULL;
}
int main() {
pthread_t threads[2];
for (long i = 0; i < 2; i++) {
pthread_create(&threads[i], NULL, printHello, (void*)i);
}
for (int i = 0; i < 2; i++) {
pthread_join(threads[i], NULL);
}
return 0;
}
Hello from Thread 0
Hello from Thread 1
(순서 뒤바뀔 수 있음)
#include <iostream>
#include <thread>
void printHello(int id) {
std::cout << "Hello from Thread " << id << std::endl;
}
int main() {
std::thread t1(printHello, 1);
std::thread t2(printHello, 2);
t1.join();
t2.join();
return 0;
}
Hello from Thread 2
Hello from Thread 1
(순서 뒤바뀔 수 있음)
(출처: https://comic.browserling.com/53)
기본연산 \ 언어 | Java | Javascript | C++ | Python |
---|---|---|---|---|
Mutex(lock) | O (ReentrantLock) |
? (Atomics) |
O (C++20) |
O |
Semaphore | O | X | O (C++20) |
O |
Critical Section | O (synchronized) |
X | X | X |
Conditional Variable | O | X | O | O |
Read-Write Lock | O | X | O | X |
(Cyclic) Barrier | O | X | O (C++20) |
O |
Countdown Latch | O | X | O (C++20) |
X |
Phaser | O | X | X | X |
Exchanger | O | X | X | X |
public class VirtualThreadExample {
public static void main(String[] args) {
for (int i = 0; i < 1_000_000; i++) {
Thread.startVirtualThread(() -> {
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
});
}
}
}
let myPromise = new Promise(function(resolve, reject) {
try {
...
resolve("완료");
} catch (error) {
reject(new Error("에러 발생!"));
}
});
myPromise.then((result) => {
console.log(result);
}).catch((error) => {
console.error(error);
});
std::promise<int> p;
std::future<int> f = p.get_future();
std::thread( [&p]{ p.set_value_at_thread_exit(9); }).detach();
this_thread::sleep_for(chrono::seconds(1));
try {
f.get();
} catch (const std:exception& e) {
...
}
CompletableFuture<String> future = CompletableFuture.supplyAsync(() -> "future example");
future.get();
def test_generator():
yield 1
yield 2
yield 3
gen = test_generator()
next(gen)
next(gen)
next(gen)
next(gen) # exception
def simple_coroutine():
print('Coroutine started')
x = yield
print('Coroutine received:', x)
coro = simple_coroutine()
next(coro)
coro.send(42)
중단/재개
-> suspend(yield) / resume재진입
가능#include <stdio.h>
#include <setjmp.h>
jmp_buf main_routine_buf, coroutine_buf;
void coroutine() {
printf("Coroutine start\n");
if (setjmp(coroutine_buf) == 0) {
longjmp(main_routine_buf, 1);
}
printf("Coroutine end\n");
}
int main() {
printf("Main start\n");
if (setjmp(main_routine_buf) == 0) {
coroutine();
} else {
printf("Back in main\n");
longjmp(coroutine_buf, 1);
}
printf("Main end\n");
return 0;
}
Main start
Coroutine start
Back in main
Coroutine end
Main end
(출처: https://www.reddit.com/r/programminghumor/comments/j6cvwj/async_await/)
async function fetchData(url) {
let response = await fetch(url);
let data = await response.json();
console.log(data);
}
fetchData("https://api.example.com/data");
import asyncio
async def say_hello(delay):
await asyncio.sleep(delay)
print(f"Hello after {delay} seconds!")
async def main():
task1 = asyncio.create_task(say_hello(1))
task2 = asyncio.create_task(say_hello(2))
await task1
await task2
asyncio.run(main())
import asyncio
import time
def blocking_io():
time.sleep(1)
return "I/O operation completed."
async def main():
loop = asyncio.get_running_loop()
result = await loop.run_in_executor(None, blocking_io)
print(result)
asyncio.run(main())
import asyncio
async def worker(name, seconds):
print(f"Worker {name} started, will sleep for {seconds} seconds")
await asyncio.sleep(seconds)
print(f"Worker {name} finished after {seconds} seconds")
async def main():
tasks = [
worker("A", 5),
worker("B", 3),
worker("C", 2),
worker("D", 4)
]
await asyncio.gather(*tasks)
asyncio.run(main())
#include <iostream>
#include <coroutine>
using namespace std;
struct task {
struct promise_type {
task get_return_object() { return {}; }
suspend_never initial_suspend() { return {}; }
suspend_never final_suspend() noexcept { return {}; }
void return_void() {}
void unhandled_exception() {}
};
};
task simple_coroutine() {
cout << "inside coroutine!" << endl;
co_return;
cout << "end of coroutine" << endl;
}
int main() {
cout << "main start" << endl;
simple_coroutine();
cout << "main end" << endl;
return 0;
}
main start
inside coroutine!
main end
task 구조체와 promise_type 구조체는 사실 상 추상 클래스에 가까워서 필요한 기능을 추가 구현해야 할 수도 있음
#include <iostream>
#include <coroutine>
using namespace std;
struct task {
struct promise_type {
task get_return_object() { return task(handle_type::from_promise(*this)); }
suspend_always initial_suspend() { return {}; }
suspend_never final_suspend() noexcept { return {}; }
void return_void() {}
void unhandled_exception() {}
};
using handle_type = coroutine_handle<promise_type>;
handle_type coro;
task(handle_type h) : coro(h) {}
~task() { if (coro) coro.destroy(); }
void resume() { if (!coro.done()) coro.resume(); }
};
task simple_coroutine() {
cout << "Before suspension" << endl;
co_await suspend_always{};
cout << "After suspension" << endl;
co_return;
}
int main() {
auto t = simple_coroutine();
cout << "Coroutine created but not yet resumed." << endl;
t.resume();
cout << "Coroutine resumed and completed." << endl;
return 0;
}
Coroutine created but not yet resumed.
Before suspension
Coroutine resumed and completed.
(출처: https://www.reddit.com/r/ProgrammerHumor/comments/10s12uf/c_meetup/)
#include <iostream>
#include <future>
int main() {
auto future1 = std::async(std::launch::async, []() {
std::this_thread::sleep_for(std::chrono::seconds(1));
return 42;
});
auto future2 = std::async(std::launch::async, []() {
std::this_thread::sleep_for(std::chrono::seconds(2));
return 99;
});
int result1 = future1.get();
int result2 = future2.get();
std::cout << "Result from task1: " << result1 << std::endl;
std::cout << "Result from task2: " << result2 << std::endl;
return 0;
}
Result from task1: 42
Result from task2: 99
채널이나 메시지큐
를 이용package main
import (
"fmt"
"time"
)
func sender(ch chan int) {
for i := 0; i < 5; i++ {
fmt.Println("Sending:", i)
ch <- i // 값을 채널에 송신
time.Sleep(time.Second)
}
close(ch)
}
func receiver(ch chan int) {
for {
value, ok := <-ch // 채널로부터 값 수신
if !ok {
fmt.Println("Channel closed!")
break
}
fmt.Println("Received:", value)
}
}
func main() {
ch := make(chan int)
go sender(ch)
go receiver(ch)
time.Sleep(6 * time.Second)
}
Sending: 0
Received: 0
Sending: 1
Received: 1
Sending: 2
Received: 2
Sending: 3
Received: 3
Sending: 4
Received: 4
Channel closed!
(출처: https://namu.wiki/w/암컷이든 수컷이든 맛있으면 그만 아닐까%3F)
자신이 사용하는 언어에서 제공하는 적당한 수준으로 추상화된 기술을 적절히 구사하면 됨