League Of Legends - Link Select [02์ฃผ์ฐจ] ๋ฉ€ํ‹ฐ์ฝ”์–ด HW & DataRace
๋ณธ๋ฌธ ๋ฐ”๋กœ๊ฐ€๊ธฐ
๐Ÿค“ Study/MultiThread

[02์ฃผ์ฐจ] ๋ฉ€ํ‹ฐ์ฝ”์–ด HW & DataRace

by GAMEMING 2024. 4. 18.
728x90

 

- ๋ฉ€ํ‹ฐ์“ฐ๋ ˆ๋“œ ํ”„๋กœ๊ทธ๋ž˜๋ฐ ์ฃผ์š” ์‚ฌํ•ญ

 

 : ์˜ฌ๋ฐ”๋ฅธ ๊ฒฐ๊ณผ๊ฐ€ ๋‚˜์™€์•ผ ํ•จ ( ๋ฌดํ•œ๋ฃจํ”„์— ๋น ์ง€๊ฑฐ๋‚˜, ํ”„๋กœ๊ทธ๋žจ์ด ์˜ค๋ฅ˜๋กœ ์ข…๋ฅ˜๋˜๋ฉด ์•ˆ๋จ )

 : ์ด๋ฅผ ์‚ฌ์šฉํ•œ ์„ฑ๋Šฅํ–ฅ์ƒ์ด ์ปค์•ผํ•จ ( ์ ์œผ๋ฉด ๋ฉ€ํ‹ฐ์“ฐ๋ ˆ๋“œ๋ฅผ ์“ฐ๋Š” ์ด์œ ๊ฐ€ ์—†์Œ )

 : ๋ฉ€์“ฐ ํ”„๋กœ๊ทธ๋ž˜๋ฐ์€ ํ•˜๋‚˜์˜ ํ”„๋กœ๊ทธ๋žจ์„ ๋‚˜๋ˆ ์„œ ์ž‘์„ฑํ•˜๋Š” ๊ฒƒ

 

 

 

- ์œ„์—์„œ ํ‹€๋ฆฐ ๊ฒฐ๊ณผ๊ฐ€ ๋‚˜์˜จ ์ด์œ 

 : Data Race -> sum += 2

 : ๊ณต์œ  ๋ฉ”๋ชจ๋ฆฌ๋ฅผ ์—ฌ๋Ÿฌ ์“ฐ๋ ˆ๋“œ์—์„œ ์ฝ๊ณ  ์“ฐ๊ณ , ์ด ์ˆœ์„œ์— ๋”ฐ๋ผ ์‹คํ–‰ ๊ฒฐ๊ณผ๊ฐ€ ์˜ˆ์ƒ๊ณผ๋Š” ๋‹ฌ๋ผ์ง„๋‹ค

 : Data Race  ⇒ ๋ณต์ˆ˜์˜ ์“ฐ๋ ˆ๋“œ๊ฐ€ ํ•˜๋‚˜์˜ ๋ฉ”๋ชจ๋ฆฌ์— ๋™์‹œ์— ์ ‘๊ทผ & ์ ์–ด๋„ ํ•œ ๊ฐœ์˜ writ

 : ์ฝ๊ณ  - ๋”ํ•˜๊ณ  - ์“ฐ๋Š” ์ด ์‚ฌ์ด์— context switching์ด ์ผ์–ด๋‚˜์„œ ๋ฌธ์ œ  (๋™์‹œ ์ ‘๊ทผ -> read, write)

 

โ”€ ์•ž์˜ ํ”„๋กœ๊ทธ๋žจ์„ ์‹ฑ๊ธ€ ์ฝ”์–ด์—์„œ ๋™์ž‘์‹œํ‚ค๋ฉด?
โ”€ ์•ž์˜ ํ”„๋กœ๊ทธ๋žจ์„ “sum+=2”๋กœ ๋ฐ”๊พธ๋ฉด?
โ”€ ์•ž์˜ ํ”„๋กœ๊ทธ๋žจ์˜ “sum+=2”๋ฅผ “_asm add sum,2”๋กœ ๋ฐ”๊พธ๋ฉด?
โ”€ “_asm add sum,2”๋กœ ๋ฐ”๊พผ ํ›„ ์‹ฑ๊ธ€ ์ฝ”์–ด์—์„œ ๋™์ž‘?

 

4๋ฒˆ์งธ์˜ ๊ฒฝ์šฐ๋ฅผ ์ œ์™ธํ•˜๊ณ  ์˜ฌ๋ฐ”๋ฅธ ๊ฐ’์ด ๋‚˜์˜ค์ง€ ์•Š๋Š”๋‹ค.

→ Data Race๋ฅผ ์—†์• ๋ฉด ๋œ๋‹ค

Lock / Unlock ์‚ฌ์šฉ : ์—ฌ๋Ÿฌ ๊ฐœ์˜ ์“ฐ๋ ˆ๋“œ๊ฐ€ ๋™์‹œ์— ์ ‘๊ทผํ•  ์ˆ˜ ์—†๋„๋ก ํ•จ (๋™์‹œ์— ํ•˜๋‚˜๋งŒ ์ ‘๊ทผ ํ•˜๋„๋ก ํ•œ๋‹ค)

 

 

 

- Lock๊ณผ Unlock

#include <iostream>
#include <thread>
#include <mutex>

int sum;
std::mutex m1;

void thread_work()
{
	for (auto i = 0; i < 25000000; ++i) {

		m1.lock();
		// Critical Section
		sum = sum + 2;
		m1.unlock();
	}
}

int main()
{
	std::thread t1{ thread_work };
	std::thread t2{ thread_work };

	t1.join();
	t2.join();

	std::cout << "sum = " << sum << std::endl;
}

 

 

 : Mutex ๊ฐ์ฒด๋Š” ์ „์—ญ ๋ณ€์ˆ˜๋กœ ์„ ์–ธํ•˜๊ณ  ๊ฐ™์€ ๊ฐ์ฒด ์‚ฌ์ด์—์„œ๋งŒ Lock๊ณผ Unlock์ด ๋™์ž‘ํ•˜๋„๋ก ํ•œ๋‹ค.

 : ์„œ๋กœ ๋™์‹œ์— ์‹คํ–‰๋˜์–ด๋„ ๊ดœ์ฐฎ์€ critical section์ด ์กด์žฌํ•˜๋ฉด ๋‹ค๋ฅธ mutex๊ฐ์ฒด๋กœ ๋ณดํ˜ธํ•˜๋Š” ๊ฒƒ์ด ์ข‹๋‹ค 

→ ๊ฐ™์€ mutex๋ฅผ ์‚ฌ์šฉํ•˜๋ฉด ๋™์‹œ์— ์‹คํ–‰์ด ๋ถˆ๊ฐ€๋Šฅ ํ•จ

 

์„œ๋กœ ์ƒํ˜ธ ๋ฐฐ์ œ๋ฅผ ํ•ด์•ผ ํ•˜๋Š”๋ฐ ๋ชจ๋“  ํฌ๋ฆฌํ‹ฐ์ปฌ ์„น์…˜์„ ๋‹ค ์ƒํ˜ธ ๋ฐฐ์ œ๋ฅผ ํ•ด์•ผ ํ•˜๋Š”๊ฐ€?
no (์„ฑ๋Šฅ ์ €ํ•˜), ๊ฐ™์ด ์‹คํ–‰ ๋˜์–ด๋„ ๋ฌธ์ œ๊ฐ€ ์—†์œผ๋ฉด ์•ˆ ํ•ด๋„ ๋จ. ๋”ฐ๋ผ์„œ ๊ฐ์ฒด๋กœ ์„ ์–ธํ•ด์„œ ๊ตฌํ˜„ํ•จ.

 

 

[ Lock()์„ ์‚ฌ์šฉํ•œ ํ”„๋กœ๊ทธ๋žจ๊ณผ Lock()์„ ์‚ฌ์šฉํ•˜์ง€ ์•Š์€ ํ”„๋กœ๊ทธ๋žจ์˜ ์†๋„ ๋น„๊ต ]

 

No lock
Lock

 

 

 →  ๊ทผ๋ฐ ์™œ No lock์ธ๋ฐ ์—ฐ์‚ฐ ๊ฒฐ๊ณผ๊ฐ€ 1์–ต์ด ๋‚˜์˜ค๋Š”๊ฐ€? DataRace๋กœ ์ธํ•ด ์ž˜๋ชป๋œ ๊ฒฐ๊ณผ ๊ฐ’์ด ๋‚˜์™€์•ผ ํ•˜๋Š”๊ฑฐ ์•„๋‹Œ๊ฐ€?

 → ํ˜„์žฌ Release ๋ชจ๋“œ๋กœ ์‹คํ–‰ ไธญ → vs ์ปดํŒŒ์ผ๋Ÿฌ ์ธ๊ณต์ง€๋Šฅ์— ์˜ํ•ด ์ž๋™ ์ตœ์ ํ™”๋จ (๋ฃจํ”„ ์•ˆ๋Œ์•„๊ฐ€๊ณ  ๋‹จ์ˆœ ๋ ˆ์ง€์Šคํ„ฐ ์—ฐ์‚ฐ ์ฒ˜๋ฆฌ )

 → ์ตœ์ ํ™”๋ฅผ ํ•˜์ง€ ์•Š๊ธฐ ์œ„ํ•ด ๋ณ€์ˆ˜๋ฅผ volatile์„ ์‚ฌ์šฉํ•˜์—ฌ ์„ ์–ธํ•ด์ฃผ๋ฉด ์ตœ์ ํ™” ๋˜์ง€ ์•Š์€ ๊ฐ’์ด ๋‚˜์˜ด

 

volatile + No lock

#include <iostream>
#include <thread>
#include <mutex>
#include <chrono>
#include <vector>

using namespace std;
using namespace std::chrono;

volatile int sum;
mutex a;

// ์ „์—ญ๋ณ€์ˆ˜๋ฅผ ์ตœ๋Œ€ํ•œ ๋งŒ๋“ค์ง€๋งˆ๋ผ -> ํ•จ์ˆ˜ ๋งค๊ฐœ๋ณ€์ˆ˜๋กœ ๋„˜๊ฒจ๋ผ
void thread_work(const int num_threads)
{
	for (auto i = 0; i < 5000'0000 / num_threads; ++i) {
		// a.lock();
		sum = sum + 2;
		// a.unlock();
	}
}

int main()
{
	/*char ch;
	cin >> ch;*/

	for (int num_threads = 1; num_threads <= 16; num_threads *= 2) {
		sum = 0;
		auto start_t = high_resolution_clock::now();
		vector<thread> threads;
		for (int i = 0; i < num_threads; ++i)
			threads.emplace_back(thread_work, num_threads);
		for (auto& th : threads)
			th.join();
		auto exec_t = high_resolution_clock::now() - start_t;
		auto ms = duration_cast<milliseconds>(exec_t).count();

		std::cout << "Thread : " << num_threads << ", sum = " << sum << ", Time = " << ms << "ms" << endl;

	}
}

 

 

- Lock() : ํ•œ ๋ฒˆ์— ํ•˜๋‚˜์˜ ์“ฐ๋ ˆ๋“œ๋งŒ์„ ์‹คํ–‰ ์‹œํ‚ค๊ธฐ์— ๋ณ‘๋ ฌ์„ฑ์ด ๊ฐ์†Œํ•จ, Lock์„ ์–ป์ง€ ๋ชปํ•˜๋ฉด Queue์— ์ˆœ์„œ๋ฅผ ์ €์žฅํ•˜๊ณ  ์Šคํ•€

- Lock ์ž์ฒด๊ฐ€ ์˜ค๋ฒ„ํ—ค๋“œ์ด๊ธฐ์— ์‹ฌ๊ฐํ•˜๊ฒŒ ์„ฑ๋Šฅ์ด ์ €ํ•˜๋˜๋Š” ํ˜„์ƒ์„ ๋ณผ ์ˆ˜ ์žˆ์Œ

 

 

 → ํ•ด๊ฒฐ๋ฐฉ๋ฒ•์€?

 → Lock์„ ์•ˆ์“ฐ๋ฉด ๋จ. Sum += 2๋ฅผ ํ•  ๋™์•ˆ ๋‹ค๋ฅธ thread๊ฐ€ ์‹คํ–‰๋˜์ง€ ๋ชปํ•˜๋„๋ก ํ•˜๋ฉด ๋จ

 → atomic : lcok์—†์ด ์ƒํ˜ธ๋ฐฐ์ œ๋ฅผ ๊ณ ๋ คํ•ด์„œ ๊ตด๋Ÿฌ๊ฐ, ํ•จ๋ถ€๋กœ ์ตœ์ ํ™”ํ•˜์ง€ ์•Š์Œ, ์ •ํ•ด์ง„ ์ˆœ์„œ๋Œ€๋กœ ์ฝ๊ณ  ์”€. atomic ์—ฐ์‚ฐ๋ผ๋ฆฌ๋„ ์‹คํ–‰์ˆœ์„œ ๋ฐ”๋€Œ์ง€ ์•Š์Œ + ๊ทผ๋ฐ ๋‹ค๋ฅธ ์—ฐ์‚ฐ์ด๋ž‘๋„ ๋ฐ”๊พธ์ง€ ์•Š์Œ

 

 

atomic

 

#include <iostream>
#include <thread>
#include <mutex>
#include <chrono>
#include <vector>
#include <atomic>

using namespace std;
using namespace std::chrono;

atomic <int> sum = 0;
mutex a;

void thread_work(const int num_threads)
{
	for (auto i = 0; i < 5000'0000 / num_threads; ++i) {
		// a.lock();
		sum = sum + 2;
		// a.unlock();
	}
}

int main()
{
	/*char ch;
	cin >> ch;*/

	for (int num_threads = 1; num_threads <= 16; num_threads *= 2) {
		sum = 0;
		auto start_t = high_resolution_clock::now();
		vector<thread> threads;
		for (int i = 0; i < num_threads; ++i)
			threads.emplace_back(thread_work, num_threads);
		for (auto& th : threads)
			th.join();
		auto exec_t = high_resolution_clock::now() - start_t;
		auto ms = duration_cast<milliseconds>(exec_t).count();

		std::cout << "Thread : " << num_threads << ", sum = " << sum << ", Time = " << ms << "ms" << endl;

	}
}

 

 

 - ๋ฌธ์ œ ๋ฐœ์ƒ ) ์ƒ๊ฐ๋ณด๋‹ค ์„ฑ๋Šฅ์ด ๊ทน์ ์œผ๋กœ ๋งŽ์ด ์ค„์ง€๋Š” ์•Š์•˜๊ณ , ๊ฐ’๋„ ์—‰ํ„ฐ๋ฆฌ๋กœ ๋‚˜์˜ด.

sum += 2

 

 - sum += 2์™€ sum = sum + 2๋Š” ๊ฒฐ๊ณผ๊ฐ’์ด ๋‹ค๋ฅด๋‹ค (์œ„์˜ ์‚ฌ์ง„)

 

_asm add sum,2
_asm lock add sum, 2;

 

 

 

 → ๊ทธ๋Ÿผ ์–ด๋–ป๊ฒŒ ํ•ด?

 → ์ฒ˜์Œ๋ถ€ํ„ฐ DataRace๊ฐ€ ์ ๋„๋ก ์ž‘์„ฑํ•˜๋ฉด ์ข‹๋‹ค

 → Lock์ด๋‚˜ Atomic ์—ฐ์‚ฐ์„ ์™„์ „ํžˆ ์—†์• ๋Š” ๊ฒƒ์ด ๊ฐ€๋Šฅํ•œ๊ฐ€?

 → No.   

// Data Race ์ตœ์†Œํ™”
void optimal_thread_work(const int num_threads)
{
	volatile int local_sum = 0;
	for (auto i = 0; i < 5000'0000 / num_threads; ++i)
		local_sum += 2;

	a.lock();
	sum += local_sum;
	a.unlock();
}

 

 

 

 → ๋‹ค๋ฅธ ์ •๋‹ต์€ ์žˆ์„๊นŒ?

volatile int sum;
volatile int sum_arr[16 * 16];
mutex a;

void thread_work(const int num_threads, const int th_id)
{
	volatile int local_sum = 0;
	for (auto i = 0; i < 5000'0000 / num_threads; ++i) {
		sum_arr[th_id * 16] = sum_arr[th_id * 16] + 2;
	}
}

int main()
{
	for (int num_threads = 1; num_threads <= 16; num_threads *= 2) {
		sum = 0;
		auto start_t = high_resolution_clock::now();
		vector<thread> threads;
		for (int i = 0; i < num_threads; ++i)
			threads.emplace_back(thread_work, num_threads, i);

		for (auto& th : threads)
			th.join();

		auto exec_t = high_resolution_clock::now() - start_t;
		auto ms = duration_cast<milliseconds>(exec_t).count();

		std::cout << "Thread : " << num_threads << ", sum = " << sum << ", Time = " << ms << "ms" << endl;

	}
}

 

Cache Thrashing - Invalidation PingPong ๋ฐœ์ƒํ•  ์ˆ˜๋„.

→ ์›์ธ์€ False Sharing์ด๋‹ค.

 

์ •๋‚ดํ›ˆ ๊ต์ˆ˜๋‹˜ ๊ฐ•์˜์ž๋ฃŒ - Cache Thrashing

 

 

 : Cache Thrashing - CPU์˜ ์บ์‹œ ๋ฉ”๋ชจ๋ฆฌ๊ฐ€ ๊ณ„์† ๋ฌดํšจํ™”๋˜๊ณ  ๋‹ค์‹œ ์ฑ„์›Œ์ง€๋Š” ํ˜„์ƒ

 : Invalidation PingPong - ๋‘ ๊ฐœ ์ด์ƒ์˜ ์ฝ”์–ด๊ฐ€ ๋™์ผํ•œ ๋ฐ์ดํ„ฐ์— ๋™์‹œ์— ์ ‘๊ทผํ•˜์—ฌ ๊ทธ ๋ฐ์ดํ„ฐ์˜ ์บ์‹œ ๋ผ์ธ์„ ๋ฒˆ๊ฐˆ์•„ ๋ฌดํšจํ•จ

 : False Sharing - ๋‘ ๊ฐœ ์ด์ƒ์˜ ์ฝ”์–ด๊ฐ€ ๋™์‹œ์— ์ ‘๊ทผํ•˜๋Š” ๋ฉ”๋ชจ๋ฆฌ ์˜์—ญ์ด ๊ฐ™์€ ์บ์‹œ๋ผ์ธ์— ์œ„์น˜ํ•ด ๋ฐœ์ƒํ•จ. ๊ณต์œ ๋˜์ง€ ์•Š์€ ๋ฉ”๋ชจ๋ฆฌ์— ๋Œ€ํ•œ ๋ฌธ์ œ. 

 

๊ด€๋ จ ๊ธ€์€ ์ด ๊ธ€์„ ์ฐธ๊ณ ํ•˜์ž   https://hwan-shell.tistory.com/230

 

C++ false sharing์ด๋ž€?(๊ฑฐ์ง“ ๊ณต์œ )

1. false sharing ์ด๋ž€?? false sharing์€ ๋ฉ€ํ‹ฐ ์“ฐ๋ ˆ๋“œ ํ™˜๊ฒฝ + CPU์˜ ๋ฉ€ํ‹ฐ ์ฝ”์–ด์—์„œ ๋ฐœ์ƒ๋ฉ๋‹ˆ๋‹ค. cpu ๋‚ด๋ถ€์˜ ์ฝ”์–ด์™€ ์ฝ”์–ด๊ฐ„์˜ ๋ฉ”๋ชจ๋ฆฌ ์ •๋ณด๊ฐ€ ๊ณต์œ ๋˜์–ด ํ•˜๋“œ์›จ์–ด ์ ์œผ๋กœ ๋ณ‘๋ชฉํ˜„์ƒ์ด ์ผ์–ด๋‚˜๋Š” ๊ฒƒ์„ ๋œปํ•ฉ๋‹ˆ๋‹ค.

hwan-shell.tistory.com

 

 

Cache Thrashing ํ•ด๊ฒฐ

 : ์“ฐ๋ ˆ๋“œ ๋งˆ๋‹ค ์„œ๋กœ ๋‹ค๋ฅธ ์บ์‹œ ๋ผ์ธ์„ ์‚ฌ์šฉํ•˜๋„๋ก ํ•œ๋‹ค. alignas ํ‚ค์›Œ๋“œ ์‚ฌ์šฉ or ํŒจ๋”ฉ(padding)

volatile int sum = 0;
struct NUM {
	alignas(64) volatile int sum;
};

NUM sum_arr[16];
mutex a;

void thread_work(const int num_threads, const int th_id)
{
	for (auto i = 0; i < 5000'0000 / num_threads; ++i) {
		sum_arr[th_id].sum = sum_arr[th_id].sum + 2;
	}
}

int main()
{
	for (int num_threads = 1; num_threads <= 16; num_threads *= 2) {
		sum = 0;
		for (auto& s : sum_arr) s.sum = 0;
		auto start_t = high_resolution_clock::now();
		vector<thread> threads;
		for (int i = 0; i < num_threads; ++i)
			threads.emplace_back(thread_work, num_threads, i);

		for (auto& th : threads)
			th.join();

		for (int i = 0; i < num_threads; ++i)
			sum = sum + sum_arr[i].sum;
		auto exec_t = high_resolution_clock::now() - start_t;
		auto ms = duration_cast<milliseconds>(exec_t).count();

		std::cout << "Thread : " << num_threads << ", sum = " << sum << ", Time = " << ms << "ms" << endl;
	}

	sum = 0;
	auto start_t2 = high_resolution_clock::now();
	for (int i = 0; i < 5000'0000; ++i)
		sum = sum + 2;
	auto exec_t2 = high_resolution_clock::now() - start_t2;
	auto ms2 = duration_cast<milliseconds>(exec_t2).count();

	std::cout << "sum = " << sum << ", Time = " << ms2 << "ms" << endl;
}

 

alignas

 

 

< ์ด๊ฒƒ์€ ๊ผญ ์•Œ์ž >
- ๋ณ‘๋ ฌ ์ปดํ“จํŒ…์ด๋ž€ ๋ฌด์—‡์ธ๊ฐ€?
- ์“ฐ๋ ˆ๋“œ๋ž€ ๋ฌด์—‡์ธ๊ฐ€?
- ์™œ ๋ฉ€ํ‹ฐ์“ฐ๋ ˆ๋“œ ํ”„๋กœ๊ทธ๋ž˜๋ฐ์„ ํ•ด์•ผ ํ•˜๋Š”๊ฐ€?
- ๋ฉ€ํ‹ฐ์“ฐ๋ ˆ๋“œ ํ”„๋กœ๊ทธ๋ž˜๋ฐ์€ ์–ด๋–ป๊ฒŒ ํ•˜๋Š”๊ฐ€?
- ๋ฉ€ํ‹ฐ์“ฐ๋ ˆ๋“œ ํ”„๋กœ๊ทธ๋ž˜๋ฐ์˜ ์–ด๋ ค์›€
- Data Race
- ์„ฑ๋Šฅ

 

 

 

 

- ๋ฉ€ํ‹ฐ์“ฐ๋ ˆ๋“œ ํ”„๋กœ๊ทธ๋ž˜๋ฐ์˜ ์ข…๋ฅ˜

 1) Heterogeneous ๋ฉ€ํ‹ฐ์“ฐ๋ ˆ๋”ฉ

 : ์“ฐ๋ ˆ๋“œ ๋งˆ๋‹ค ๋งก์€ ์—ญํ• ์ด ๋‹ค๋ฆ„

 : ๋‹ค๋ฅธ ์ฝ”๋“œ ํŒŒํŠธ๋ฅผ ์‹คํ–‰ํ•˜๊ธฐ ๋•Œ๋ฌธ์— ์“ฐ๋ ˆ๋“œ ๊ฐ„์˜ Load Balancing(๋ถ€ํ•˜ ๋ถ„์‚ฐ) ํž˜๋“ฆ 

 : ๋ณ‘๋ ฌ์„ฑ์ด ์ œํ•œ๋จ

 

 2) Homogeneous ๋ฉ€ํ‹ฐ์“ฐ๋ ˆ๋”ฉ

 : Data/Event Driven ํ”„๋กœ๊ทธ๋ž˜๋ฐ

 : ๋ชจ๋“  ์“ฐ๋ ˆ๋“œ๋Š” Symmetric(๋Œ€์นญ์ )ํ•จ ๋™์ผํ•œ ์—ญํ• ์„ ์ˆ˜ํ–‰

 : ์ž๋™์ ์ธ Load Balancing

 : ๋ณ‘๋ ฌ์„ฑ ์ œํ•œ ์—†์Œ

 : ์ž‘์—… ๋ถ„๋ฐฐ Queue๋ฅผ ๋น„๋กฏํ•œ ์ผ๋ฐ˜์  ๋ณ‘๋ ฌ ์ž๋ฃŒ๊ตฌ์กฐ ํ•„์š”

 

 

 

- ๊ฒŒ์ž„ ์„œ๋ฒ„ (MMORPG)

 : Window ๋ฉ€ํ‹ฐ์“ฐ๋ ˆ๋“œ + Network I/O API์ธ IOCP

 : ์ผ๋ฐ˜์  Select()์œผ๋กœ๋Š” ๋ช‡ ์ฒœ๊ฐœ์˜ Socket ์„ ๊ด€๋ฆฌํ•  ์ˆ˜ ์—†์œผ๋ฉฐ ์†Œ์ผ“ ํ•˜๋‚˜๋‹น ํ•˜๋‚˜์˜ ์“ฐ๋ ˆ๋“œ๋Š” OS์˜ ๊ณผ๋ถ€ํ•˜

 : Homogeneous ๋ฉ€ํ‹ฐ์“ฐ๋ ˆ๋”ฉ Worker thread์˜ pool ์‚ฌ์šฉ(HW Core ๊ฐœ์ˆ˜์˜ 1.5๋ฐฐ, ๋„คํŠธ์›Œํฌ ๋ฐ์ดํ„ฐ ์ฒ˜๋ฆฌ์™€ AI๋ฃจํ‹ด)

 : ์†Œ์ผ“์„ ํ†ตํ•ด ํŒจํ‚ท์ด ์˜ฌ ๋•Œ ๋งˆ๋‹ค, OS๊ฐ€ thread pool์˜ ์“ฐ๋ ˆ๋“œ๋ฅผ ํ•˜๋‚˜ ๊นจ์›Œ์„œ ํŒจํ‚ท์˜ ์ฒ˜๋ฆฌ๋ฅผ ๋งก๊น€. 

 : DataBase Query - ์“ฐ๋ ˆ๋“œ์˜ blocking์„ ์ดˆ๋ž˜ํ•˜๊ธฐ์— blocking ์ „์šฉ ์“ฐ๋ ˆ๋“œ๋ฅผ ๋”ฐ๋กœ ๋‘ฌ ์ž‘์—…

 : NPC AI - ๋ณดํ†ต NPC๋Š” ๋„ˆ๋ฌด ๋งŽ์ด ์กด์žฌํ•จ, Timer ์“ฐ๋ ˆ๋“œ๋ฅผ ์‚ฌ์šฉํ•ด ํ™œ์„ฑํ™”ํ•œ NPC์˜ ์ด๋ฒคํŠธ๋งŒ์„ ์ฒ˜๋ฆฌํ•œ๋‹ค

 : ํ‰์ƒ์‹œ์— CPU ๋‚ญ๋น„๋Š” ๊ดœ์ฐฎ๋‹ค. ์ตœ๋Œ€ ๋™์ ‘์ด ์ค‘์š”