์ฉ์ด์ ๋ฆฌ
- TPL(Task Parallel Library) : ์ ํ๋ฆฌ์ผ์ด์ ์ ๋ณ๋ ฌ ์ฒ๋ฆฌ ๋ฐ ๋์์ฑ ๊ธฐ๋ฅ์ ์ถ๊ฐํ๋ ๊ณผ์ ์ ๋จ์ํํ์ฌ ๊ฐ๋ฐ์๊ฐ ๋ ์์์ ์ผ๋ก ์์ ํ ์ ์๋๋ก ํ๋ ๊ฒ
- PFX(Parallel Framework) : .NET 4.0๋ถํฐ System.Threading.Task์ ์ถ๊ฐ๋ ๋ณ๋ ฌ์ฒ๋ฆฌ ํ๋ ์์ํฌ
- ๋ณ๋ ฌ ์ปดํจํ : ์์ฐจ์ ์ธ ์ง๋ ฌ ํ๋ก๊ทธ๋จ์ ๋ถํ ํ๊ณ ๋์์ ๋ณ๋ ฌ๋ก ์ํํ๋ ํํ
- ๋ถ์ฐ ์ปดํจํ : ๋จ์ผ ๋ฌธ์ ๋ฅผ ์ฌ๋ฌ ์์ ์ผ๋ก ๋๋์ด ์ฌ๋ฌ ์ปดํจํฐ์์ ์ฒ๋ฆฌ ํ ๊ฒฐ๊ณผ๋ฅผ ๋ชจ์ผ๋ ํํ
Parallel Programming (๋ณ๋ ฌ ํ๋ก๊ทธ๋๋ฐ)
- .NET์ ๋ณ๋ ฌ ํ๋ก๊ทธ๋๋ฐ์ผ๋ก TPL์ ์ ๊ณตํ๋ฉฐ, TPL์ด ๊ฐ๋ฐ์๋ฅผ ๋์ ํ์ฌ ์ค๋ ๋ ์ํ ๋ชจ๋ํฐ๋ง, ์ ์ง ๊ด๋ฆฌ, ์ข
๋ฃ, ๋์ ์คํ ์ ์ด, ์์
์ ๋ถํ , ์ค๋ ๋ ํ ๊ด๋ฆฌ ๋ฑ ๋ฆฌ์์ค ๊ด๋ฆฌ๋ฅผ ์ง์ํด์ค๋ค.
(TPL์ System.Threading ๋ฐ System.Threading.Tasks ๋ค์์คํ์ด์ค๋ก ๊ตฌ์ฑ) - ๋ณ๋ ฌ ํ๋ก๊ทธ๋๋ฐ์ ๋น๋๊ธฐ ํ๋ก๊ทธ๋๋ฐ๊ณผ ๋ค๋ฅด๋ค. ๋ณ๋ ฌ ํ๋ก๊ทธ๋๋ฐ๊ณผ ๋น๋๊ธฐ ํ๋ก๊ทธ๋๋ฐ ๋ชจ๋ CPU ๋๋ GPU๋ฅผ ํจ์จ์ ์ผ๋ก ์ฌ์ฉํ๊ธฐ ์ํ ๊ธฐ๋ฒ์ด์ง๋ง, ์ด๋ฅผ ํจ์จ์ ์ผ๋ก ์ฌ์ฉํ๋ ๋ฐฉ๋ฒ์ด ๋ค๋ฅด๋ค.
๋ณ๋ ฌ ํ๋ก๊ทธ๋๋ฐ : ์์ ์ ๋ถํ ์ ๋ณต
๋น๋๊ธฐ ํ๋ก๊ทธ๋๋ฐ : ์ฝ๋ ํ๋ฆ์ ์ ์ฐํ๊ฒ ๋ณ๊ฒฝ
- ์์ค์ฝ๋์ ๋ฐ๋ผ ๋ณ๋ ฌ์ฒ๋ฆฌ๊ฐ ์ ํฉํ์ง ์์ ์ ์๋ค. ๋จ์ํ ์์ ์ ๋ณ๋ ฌ์ฒ๋ฆฌํ๋๊ฑด ์คํ๋ ค ์คํ ์๋ ์ ํ๋ฅผ ๋ฐ์ ์ํฌ ์ ์๋ค.
- ๋ณ๋ ฌ ํ๋ก๊ทธ๋๋ฐ์ ์์ ๋ถํ ๋ฐฉ์์ ๋ฐ๋ผ Data Parallelism๊ณผ Task Parallelism์ผ๋ก ๊ตฌ๋ถํ๋ค.
.NET์ Parallel Class
- .NET 4.0๋ถํฐ PFX๊ฐ ์ถ๊ฐ๋์ด Parallel Class ์ง์
- .NET์ Parallel ๋ฉ์๋
- Parallel.For() : 0๋ถํฐ ํน์ Index๊น์ง์ ์์ ์ ๋ณ๋ ฌ ์ฒ๋ฆฌ
- Parallel.ForEach() : List์ ์ฌ์ด์ฆ๋ฅผ ์๋ ์ธก์ ํ์ฌ ๋ณ๋ ฌ ์ฒ๋ฆฌ
- Parallel.Invoke() : ์ฌ๋ฌ ์ฝ๋๋ฅผ Action delegate๋ก ๋ฐ์์ ๋ค์ค ์ค๋ ๋๋ฅผ ํตํด ๋ณ๋ ฌ๋ก Task๋ฅผ ๋๋์ด ํ๋ฒ์ ์ฒ๋ฆฌ
Data Parallelism (๋ฐ์ดํฐ ๋ณ๋ ฌํ)
- ๋์ผํ ์ฒ๋ฆฌ๋ฅผ ๋ค์์ ๋ฐ์ดํฐ์ ์ ์ฉํ๋ ๋ฐฉ์
- .NET์์ Parallel.For(), Parallel.ForEach() ๋ฉ์๋๋ฅผ ์ ๊ณต
// ์์ฐจ์ฒ๋ฆฌ
for(int i = 0; i < 1000; i++)
{
Console.WriteLine("Thread ID = {0} / Index = {1}", Thread.CurrentThread.ManagedThreadId, i);
}
// ๋ณ๋ ฌ์ฒ๋ฆฌ : Parallel.For()
Parallel.For(0, 1000, (i) => {
Console.WriteLine("Thread ID = {0} / Index = {1}", Thread.CurrentThread.ManagedThreadId, i);
});
// ์์ฐจ ์ฒ๋ฆฌ
int[] nums = Enumerable.Range(0, 100000).ToArray();
foreach (var item in nums)
{
Console.WriteLine("Thread ID = {0}", Thread.CurrentThread.ManagedThreadId);
}
// ๋ณ๋ ฌ ์ฒ๋ฆฌ : Parallel.ForEach()
int[] nums = Enumerable.Range(0, 100000).ToArray();
Parallel.ForEach(nums, item =>
{
Console.WriteLine("Thread ID = {0}", Thread.CurrentThread.ManagedThreadId);
});
Task Parallelism (์์ ๋ณ๋ ฌํ)
- ์ผ๋ฐ์ ์ผ๋ก ์๊ฐํ๋ ๋ณ๋ ฌ ์ฒ๋ฆฌ ๋ฐฉ์
- ๋ฐ์ดํฐ ๋ณ๋ ฌํ์ ๋ฌ๋ฆฌ ๋ ๋ฆฝ์ ์ธ ์์ ๋ค์ ๋์์ ์ฒ๋ฆฌํ๋ ๋ฐฉ์
- .NET์์ Parallel.Invoke() ๋ฉ์๋๋ฅผ ์ ๊ณต
Parallel.Invoke(() => DoSomeWork(), () => DoSomeOtherWork());
๋ณ๋ ฌ ์ฒ๋ฆฌ ์ ์ดํ๊ธฐ
- ๋ณ๋ด ์ฒ๋ฆฌ์์ ๋ฐ์ํ๋ ์ค๋ฅ์ ์ฃผ ์์ธ์ ๋ค์์ ์ค๋ ๋๊ฐ ๊ณต์ ๋ฉ๋ชจ๋ฆฌ์ ์ ๊ทผํ๊ธฐ ๋๋ฌธ์ ๋ฐ์ํ๋ค.
- ๊ณต์ ๋ฉ๋ชจ๋ฆฌ ์ ๊ทผ ํ์๋ฅผ ์ต์ํ ํ ์ ์๋ ๋ฐฉ๋ฒ ์ค ํ๋๋ "์ค๋ ๋ ๋ฉ๋ชจ๋ฆฌ" ์ฌ์ฉ์ด๋ค. ์ค๋ ๋ ๋ฉ๋ชจ๋ฆฌ๋ฅผ ์ฌ์ฉํ๋ฉด ๊ณต์ ๋ฉ๋ชจ๋ฆฌ์ ๋ค์์ ์ค๋ ๋๊ฐ ๋ฐ์ดํฐ ์์ ์ ํ๋ ๋ฐ์ดํฐ ๋ ์ด์ค ํ์์ ๋ฐฉ์ง ํ ์ ์๋ค.
int[] nums = Enumerable.Range(0, 1000000).ToArray();
long total = 0; // ๊ณต์ ๋ฉ๋ชจ๋ฆฌ ๋ณ์
Parallel.For<long>(
0, // ์์
nums.Length, // ๋
() => 0, // Func<TLocal> localInit : ์ค๋ ๋ ๋ก์ปฌ ๋ณ์ ์ด๊ธฐํ ํจ์
// Func<int,ParallelLoopState,TLocal,TLocal> body : ๋ณ๋ ฌ ์ฒ๋ฆฌ ํจ์
(j, loop, subtotal) =>
{
subtotal += nums[j];
return subtotal;
},
// Action<TLocal> localFinally : ์ค๋ ๋ ๋ก์ปฌ ๋ณ์๋ฅผ ๊ณต์ ๋ฉ๋ชจ๋ฆฌ ๋ณ์์ ์ ์ฉํ๋ ํจ์
(x) => Interlocked.Add(ref total, x)
);
๋ณ๋ ฌ ์ฒ๋ฆฌ์ ์์ฐจ ์ฒ๋ฆฌ ์๋ ๋น๊ต 1
- N by M Matrix๋ฅผ ๊ณฑ์ ์ฐ์ฐํ๋ ์ฝ๋๋ฅผ ์์ฑํ์ฌ ๋ณ๋ ฌ์ฒ๋ฆฌ์ ์์ฐจ์ฒ๋ฆฌ์ ์๋๋ฅผ ์ธก์
- ํ ์คํธ ํ๊ฒฝ : CPU i5-4690 (4 Core) (CPU ํ๊ฒฝ์ ๋ฐ๋ผ ์๋๋ ๋ค๋ฅด๊ฒ ์ธก์ ๋ ์ ์์)
- ๊ฒฐ๋ก : ๋ณต์กํ ์ฐ์ฐ์์๋ ์์ฐจ ์ฒ๋ฆฌ ๋ฐฉ์๋ณด๋ค ๋ณ๋ ฌ ์ฒ๋ฆฌ ๋ฐฉ์์ ์ ์ฉ ํ์ ๋ ๋ณด๋ค ๋น ๋ฅธ ์ฐ์ฐ์๋๋ฅผ ๊ธฐ๋ ํ ์ ์์ง๋ง, ๋จ์ํ ์ฐ์ฐ์์๋ ์์ฐจ ์ฒ๋ฆฌ ๋ฐฉ์์ด ๋ ๋น ๋ฅผ ์ ์๋ค.
Matrix | ๋ณ๋ ฌ ์ฒ๋ฆฌ ์์ ์๊ฐ | ์์ฐจ ์ฒ๋ฆฌ ์์ ์๊ฐ |
1000 by 1000 | 3,925ms | 10,636ms |
2000 by 2000 | 32,305ms | 105,114ms |
3000 by 3000 | 112,568ms | 348,749ms |
4000 by 4000 | 285,057ms | 936,480ms |
5000 by 5000 | 536,731ms | 1,015,672ms |
using System;
using System.Diagnostics;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
namespace Parallel_TEST
{
class Program
{
static void Main(string[] args)
{
int x = 1000;
int y = 1000;
for (int i = 0; i < 5; i++)
{
int _X = x + (x * i); // 1000, 2000, 3000, 4000, 5000
int _Y = y + (y * i); // 1000, 2000, 3000, 4000, 5000
double[,] matA = SetMatrix(_X, _Y);
double[,] matB = SetMatrix(_X, _Y);
double[,] result = new double[_X, _Y ];
Console.WriteLine("---------------------------------");
Console.WriteLine("X : " + _X + " / " + "Y : " + _Y);
ParallelTest(matA, matB, result);
LoopTest(matA, matB, result);
Console.WriteLine("---------------------------------");
}
}
static double[,] SetMatrix(int x, int y)
{
double[,] result = new double[x, y];
for (int i = 0; i < x; i++)
{
for(int j = 0; j < y; j++)
{
result[i, j] = 1;
}
}
return result;
}
static void ParallelTest(double[,] matA, double[,] matB, double[,] result)
{
int matACols = matA.GetLength(1);
int matBCols = matB.GetLength(1);
int matARows = matA.GetLength(0);
Stopwatch stopwatch = new Stopwatch(); //๊ฐ์ฒด ์ ์ธ
stopwatch.Start(); // ์๊ฐ์ธก์ ์์
Parallel.For(0, matARows, i =>
{
for (int j = 0; j < matBCols; j++)
{
double temp = 0;
for (int k = 0; k < matACols; k++)
{
temp += matA[i, k] * matB[k, j];
}
result[i, j] = temp;
}
}); // Parallel.For
stopwatch.Stop(); //์๊ฐ์ธก์ ๋
Console.WriteLine("Parallel Time : " + stopwatch.ElapsedMilliseconds + "ms (" + stopwatch.ElapsedMilliseconds / 1000 + "sec)");
}
static void LoopTest(double[,] matA, double[,] matB, double[,] result)
{
int matACols = matA.GetLength(1);
int matBCols = matB.GetLength(1);
int matARows = matA.GetLength(0);
Stopwatch stopwatch = new Stopwatch(); //๊ฐ์ฒด ์ ์ธ
stopwatch.Start(); // ์๊ฐ์ธก์ ์์
for (int i = 0; i < matARows; i++)
{
for (int j = 0; j < matBCols; j++)
{
double temp = 0;
for (int k = 0; k < matACols; k++)
{
temp += matA[i, k] * matB[k, j];
}
result[i, j] = temp;
}
}
stopwatch.Stop(); //์๊ฐ์ธก์ ๋
Console.WriteLine("Loop Time : " + stopwatch.ElapsedMilliseconds + "ms (" + stopwatch.ElapsedMilliseconds / 1000 + "sec)");
}
}
}
๋ณ๋ ฌ ์ฒ๋ฆฌ์ ์์ฐจ ์ฒ๋ฆฌ ์๋ ๋น๊ต 2
- ์ ๋ ฅ๋ ์ ์ N์ 0๋ถํฐ N-1๊น์ง์ ํฉ์ ๊ตฌํ๋ ์ฝ๋๋ฅผ ์์ฑํ์ฌ ๋ณ๋ ฌ์ฒ๋ฆฌ์ ์์ฐจ์ฒ๋ฆฌ์ ์๋๋ฅผ ์ธก์
- ํ ์คํธ ํ๊ฒฝ : CPU i5-4690 (4 Core) (CPU ํ๊ฒฝ์ ๋ฐ๋ผ ์๋๋ ๋ค๋ฅด๊ฒ ์ธก์ ๋ ์ ์์)
Number | ๋ณ๋ ฌ ์ฒ๋ฆฌ ์์ ์๊ฐ | ์์ฐจ ์ฒ๋ฆฌ ์์ ์๊ฐ |
1,000,000,000 | 2,677ms | 2,194ms |
1,100,000,000 | 2,818ms | 2,473ms |
1,200,000,000 | 3,252ms | 2,806ms |
1,300,000,000 | 2,983ms | 2,985ms |
1,400,000,000 | 3,294ms | 3,186ms |
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
namespace Parallel_TEST
{
class Program
{
static void Main(string[] args)
{
long count = 1000000000; // 1000000000
for (int i = 0; i < 5; i++)
{
long _count = count + (100000000 * i);
Console.WriteLine("---------------------------------");
Console.WriteLine("Count : " + _count);
ParallelTest2(_count);
LoopTest2(_count);
Console.WriteLine("---------------------------------");
}
}
static void ParallelTest2(long count)
{
long sum = 0;
Stopwatch stopwatch = new Stopwatch(); //๊ฐ์ฒด ์ ์ธ
stopwatch.Start(); // ์๊ฐ์ธก์ ์์
Parallel.For<long>(
0,
count,
() => 0,
(j, LoopTest, subsum) =>
{
subsum += j;
return subsum;
},
(x) => Interlocked.Add(ref sum, x)
);
stopwatch.Stop(); //์๊ฐ์ธก์ ๋
Console.WriteLine("SUM : " + sum);
Console.WriteLine("Parallel Time : " + stopwatch.ElapsedMilliseconds + "ms (" + stopwatch.ElapsedMilliseconds / 1000 + "sec)");
}
static void LoopTest2(long count)
{
long sum = 0;
Stopwatch stopwatch = new Stopwatch(); //๊ฐ์ฒด ์ ์ธ
stopwatch.Start(); // ์๊ฐ์ธก์ ์์
for(int i = 0; i < count; i++)
{
sum += i;
}
stopwatch.Stop(); //์๊ฐ์ธก์ ๋
Console.WriteLine("SUM : " + sum);
Console.WriteLine("Loop Time : " + stopwatch.ElapsedMilliseconds + "ms (" + stopwatch.ElapsedMilliseconds / 1000 + "sec)");
}
}
๋ณ๋ ฌ ์ฒ๋ฆฌ์ ์์ฐจ ์ฒ๋ฆฌ ์๋ ๋น๊ต ๊ฒฐ๋ก
- ๋ณต์กํ ์ฐ์ฐ์์๋ ์์ฐจ ์ฒ๋ฆฌ ๋ฐฉ์๋ณด๋ค ๋ณ๋ ฌ ์ฒ๋ฆฌ ๋ฐฉ์์ ์ ์ฉํ์ ๋, ๋น ๋ฅธ ์ฐ์ฐ์๋๋ฅผ ๊ธฐ๋ํ ์ ์์ง๋ง, ๋จ์ํ ์ฐ์ฐ์์๋ ์์ฐจ ์ฒ๋ฆฌ ๋ฐฉ์์ด ๋ ๋น ๋ฅผ ์ ์๋ค.
Parallel ํด๋์ค (System.Threading.Tasks)
๋ณ๋ ฌ ๋ฃจํ ๋ฐ ์์ญ์ ๋ํ ์ง์์ ์ ๊ณตํฉ๋๋ค.
learn.microsoft.com
[C#] ๋ณ๋ ฌ ํ๋ก๊ทธ๋๋ฐ Parallel Programming (1) - ๋ฐ์ดํฐ ๋ณ๋ ฌํ
๋ณ๋ ฌ ํ๋ก๊ทธ๋๋ฐ Parallel Programming C++ ์์ ๋ณ๋ ฌ ํ๋ก๊ทธ๋๋ฐ์ ํ๋์จ์ด ์์ค์ ์กฐ์์ด ํ์ํด ๊ต์ฅํ ์ด๋ ค์ ๊ณ ๋ฒ๊ทธ๋ ๋ง์์ต๋๋ค. ๋ ํฐ ๋ฌธ์ ๋ ๋ณ๋ ฌ ํ๋ก๊ทธ๋๋ฐ์ ์ํ ๋๋ฒ๊น ๋๊ตฌ๋ ๋ง๋ ์น
ibocon.tistory.com
Parallel ํด๋์ค - C# ํ๋ก๊ทธ๋๋ฐ ๋ฐฐ์ฐ๊ธฐ (Learn C# Programming)
๋ณ๋ ฌ ํ๋ก๊ทธ๋๋ฐ (Parallel Programming) CPU๊ฐ ํ๋์๋ ์๋์์ 2๊ฐ, 4๊ฐ์ CPU๋ฅผ ์ฅ์ฐฉํ๋ ๊ฒ์ด ๋ณดํธํ ๋จ์ ๋ฐ๋ผ, ์ด๋ฌํ ๋ณต์ CPU๋ฅผ ์ถฉ๋ถํ ํ์ฉํ๊ธฐ ์ํ ํ๋ก๊ทธ๋๋ฐ ๊ธฐ๋ฒ์ ๋ํ ์๊ตฌ๊ฐ ์ฆ๊ฐํ์
www.csharpstudy.com
[IT์ ํ ๊ฑธ์ ๋ ๋ค๊ฐ๊ฐ๊ธฐ] ์ฐ์ฐ์ฒ๋ฆฌ์ ์ฑ๋ฅ ํ๊ณ์ ๋์ ํ๋ ๋ณ๋ ฌ์ปดํจํ (5ํธ) | ์ธ์ฌ์ดํธ๋ฆฌํฌํธ
์ง๋ 4ํธ์์๋ ๋ณ๋ ฌ์ปดํจํฐ๋ฅผ ์ดํด๋ณด์์ต๋๋ค. [๊ด๋ จ๊ธฐ์ฌ ๋ฐ๋ก ๊ฐ๊ธฐ: ๋ณ๋ ฌ์ปดํจํฐ] ๊ณผ๊ฑฐ์๋ ์ํผ์ปดํจํฐ์๋ง ์ ์ฉ๋์ด ์๋ ๋ณ๋ ฌ์ปดํจํฐ ์ํคํ ์ฒ๊ฐ ํ์ฌ๋ ์ผ๋ฐ PC์๋ ๋ฒ์ฉ์ ์ผ๋ก ์ฑํ๋๊ณ ์
www.samsungsds.com
Data vs Task Parallelism in C#
Parallelism is an important concept in programming because it divides tasks and allocates those tasks to separate threads for processing. In .NET/C# for parallelism you can use the System.Threading and System.Threading.Tasks namespaces. These namespaces pr
dotnethow.net
.NET์ ๋ณ๋ ฌ ํ๋ก๊ทธ๋๋ฐ: ์ค๋ช ์ ๊ฐ์ด๋
.NET์ ๋ณ๋ ฌ ํ๋ก๊ทธ๋๋ฐ์ ๋ํ ๋ฌธ์ ๋ชฉ๋ก.
learn.microsoft.com
'๊ฐ๋ฐ๐ป > C#' ์นดํ ๊ณ ๋ฆฌ์ ๋ค๋ฅธ ๊ธ
[C#] ๋คํธ์ํฌ ํต์ - TCP&UDP (3) | 2023.06.11 |
---|---|
[C#] ChatGPT ์ฑํ ํ๋ก๊ทธ๋จ ๋ง๋ค๊ธฐ (2) | 2023.06.06 |
[C#] ๋น๋๊ธฐ ํ๋ก๊ทธ๋๋ฐ Async, Await (0) | 2023.06.05 |
[C#] GC(Garbage Collection) (0) | 2023.06.01 |
[C#] .NET Framework & .NET (.NET Core) (0) | 2023.05.25 |