- [SQLSERVER] Loại bỏ Restricted User trên database MSSQL
- [C#] Hướng dẫn tạo mã QRcode Style trên winform
- [C#] Hướng dẫn sử dụng temp mail service api trên winform
- [C#] Hướng dẫn tạo mã thanh toán VietQR Pay không sử dụng API trên winform
- [C#] Hướng Dẫn Tạo Windows Service Đơn Giản Bằng Topshelf
- [C#] Chia sẻ source code đọc dữ liệu từ Google Sheet trên winform
- [C#] Chia sẻ source code tạo mã QR MOMO đa năng Winform
- [C#] Chia sẻ source code phần mềm lên lịch tự động chạy ứng dụng Scheduler Task Winform
- [Phần mềm] Tải và cài đặt phần mềm Sublime Text 4180 full version
- [C#] Hướng dẫn download file từ Minio Server Winform
- [C#] Hướng dẫn đăng nhập zalo login sử dụng API v4 trên winform
- [SOFTWARE] Phần mềm gởi tin nhắn Zalo Marketing Pro giá rẻ mềm nhất thị trường
- [C#] Việt hóa Text Button trên MessageBox Dialog Winform
- [DEVEXPRESS] Chia sẻ code các tạo report in nhiều hóa đơn trên XtraReport C#
- [POWER AUTOMATE] Hướng dẫn gởi tin nhắn zalo từ file Excel - No code
- [C#] Chia sẻ code lock và unlock user trong domain Window
- [DEVEXPRESS] Vẽ Biểu Đồ Stock Chứng Khoán - Công Cụ Thiết Yếu Cho Nhà Đầu Tư trên Winform
- [C#] Hướng dẫn bảo mật ứng dụng 2FA (Multi-factor Authentication) trên Winform
- [C#] Hướng dẫn convert HTML code sang PDF File trên NetCore 7 Winform
- [C#] Hướng dẫn viết ứng dụng chat với Gemini AI Google Winform
[C#] Giới thiệu và hướng dẫn sử dụng Parallel trong lập trình .NET
Hôm nay mình xin giới thiệu và hướng dẫn các bạn sử dụng lớp Parallel trong C#. Vậy parallel trong C# là gì? và sử dụng nó như thế nào cho đúng.
Parallel là gì?
Parallel Class là cơ chế xử lý song song trong C#. Nhiều máy tính cá nhân và máy trạm có hai hoặc bốn lõi (CPU) cho phép nhiều luồng xử lý (Thread) được thực hiện đồng thời. Máy tính trong tương lai gần dự kiến sẽ còn có nhiều hơn số lỗi hiện tại. Để tận dụng lợi thế của phần cứng của ngày hôm nay và ngày mai, bạn có thể phân phối công việc trên nhiều luồng xử lý trên nhiều lõi. Visual Studio 2010 và .NET Framework 4 hỗ trợ tăng cường cho lập trình song song bằng cách cung cấp một runtime mới, các loại thư viện lớp mới, và các công cụ chẩn đoán mới. Những tính năng đơn giản hóa phát triển song song để bạn có thể viết hiệu quả, khả năng mở rộng và đa dạng tiến trình song song.
Trường hợp 1: Nên dùng Parallel
Một đám ruộng cần phải gặt song càng sớm càng tốt, chúng ta có 5 người( tức Parallel.For chạy từ 1 – 5) , mỗi người sẽ gặt 1/5 đám ruộng, ai song trước thì nghĩ( là Parallel.For/ForEach) . Y vậy, nếu việc gặt lúa song song cho ta lợi 3t về time và việc chia phần đám ruộng cho 5 người mất 1t thì chúng ta vẫn lợi 2t về thời gian hơn so với việc 5 người lần lược thay nhau gặt ( là for/foreach). => Parallel.* lợi hơn
Trường hợp 2: không dùng parallel
Một đám ruộng cần phải gặt song càng sớm càng tốt, chúng ta có 5 người( tức Parallel.For chạy từ 1 – 5) , vấn đề ở đây là 5 người nhưng chỉ có 1 chiếc “Liềm” nên phải share cho nhau. Vậy cuối cùng cũng chỉ có duy nhất một người gặt tại một thời điểm => chẳng khác gì thay nhau gặt cộng thêm thời gian chia phần đám ruộng cho 5 người trước khi gặt thì ta mất nhiều thời gian hơn(vi nếu bạn chia phần công việc trong code hay trước khi run ứng dụng thì lúc run-time CPU sẽ không cần thực thi việc phân chia core/thread) => for.foreach lợi hơn
Cách khai báo và sử dụng lớp Parallel trong C#.
//Cách dùng for bình thường ta vẫn hay dùng
int n = ...
for (int i = 0; i < n; i++)
{
// ...
}
//Cách dùng với lớp parallel
int n = ...
Parallel.For(0, n, i =>
{
// ...
});
//Hoặcvới một IEnumerable
IEnumerable myEnumerable = ...
Parallel.ForEach(myEnumerable, obj =>
{
// ...
});
Vẫn có thể dùng với LINQ
IEnumerable source = ...
// LINQ
var query1 = from i in source select Normalize(i);
// PLINQ = parallel LINQ
var query2 = from i in source.AsParallel()
select Normalize(i);
//Hoặc
IEnumerable myEnumerable = ...
myEnumerable.AsParallel().ForAll(obj => DoWork(obj));
Đây là bài test lý tưởng với Parallel:
namespace ParallelTests
{
class Program
{
private static int Fibonacci(int x)
{
if (x <= 1) { return 1; } return Fibonacci(x - 1) + Fibonacci(x - 2); } private static void DummyWork() { var result = Fibonacci(10); // inspect the result so it is no optimised away. // We know that the exception is never thrown. The compiler does not. if (result > 300)
{
throw new Exception("failed to to it");
}
}
private const int TotalWorkItems = 2000000;
private static void SerialWork(int outerWorkItems)
{
int innerLoopLimit = TotalWorkItems / outerWorkItems;
for (int index1 = 0; index1 < outerWorkItems; index1++)
{
InnerLoop(innerLoopLimit);
}
}
private static void InnerLoop(int innerLoopLimit)
{
for (int index2 = 0; index2 < innerLoopLimit; index2++) { DummyWork(); } } private static void ParallelWork(int outerWorkItems) { int innerLoopLimit = TotalWorkItems / outerWorkItems; var outerRange = Enumerable.Range(0, outerWorkItems); Parallel.ForEach(outerRange, index1 =>
{
InnerLoop(innerLoopLimit);
});
}
private static void TimeOperation(string desc, Action operation)
{
Stopwatch timer = new Stopwatch();
timer.Start();
operation();
timer.Stop();
string message = string.Format("{0} took {1:mm}:{1:ss}.{1:ff}", desc, timer.Elapsed);
Console.WriteLine(message);
}
static void Main(string[] args)
{
TimeOperation("serial work: 1", () => Program.SerialWork(1));
TimeOperation("serial work: 2", () => Program.SerialWork(2));
TimeOperation("serial work: 3", () => Program.SerialWork(3));
TimeOperation("serial work: 4", () => Program.SerialWork(4));
TimeOperation("serial work: 8", () => Program.SerialWork(8));
TimeOperation("serial work: 16", () => Program.SerialWork(16));
TimeOperation("serial work: 32", () => Program.SerialWork(32));
TimeOperation("serial work: 1k", () => Program.SerialWork(1000));
TimeOperation("serial work: 10k", () => Program.SerialWork(10000));
TimeOperation("serial work: 100k", () => Program.SerialWork(100000));
TimeOperation("parallel work: 1", () => Program.ParallelWork(1));
TimeOperation("parallel work: 2", () => Program.ParallelWork(2));
TimeOperation("parallel work: 3", () => Program.ParallelWork(3));
TimeOperation("parallel work: 4", () => Program.ParallelWork(4));
TimeOperation("parallel work: 8", () => Program.ParallelWork(8));
TimeOperation("parallel work: 16", () => Program.ParallelWork(16));
TimeOperation("parallel work: 32", () => Program.ParallelWork(32));
TimeOperation("parallel work: 64", () => Program.ParallelWork(64));
TimeOperation("parallel work: 1k", () => Program.ParallelWork(1000));
TimeOperation("parallel work: 10k", () => Program.ParallelWork(10000));
TimeOperation("parallel work: 100k", () => Program.ParallelWork(100000));
Console.WriteLine("done");
Console.ReadLine();
}
}
}
KẾT QUẢ:
serial work: 1 took 00:02.31
serial work: 2 took 00:02.27
serial work: 3 took 00:02.28
serial work: 4 took 00:02.28
serial work: 8 took 00:02.28
serial work: 16 took 00:02.27
serial work: 32 took 00:02.27
serial work: 1k took 00:02.27
serial work: 10k took 00:02.28
serial work: 100k took 00:02.28
parallel work: 1 took 00:02.33
parallel work: 2 took 00:01.14
parallel work: 3 took 00:00.96
parallel work: 4 took 00:00.78
parallel work: 8 took 00:00.84
parallel work: 16 took 00:00.86
parallel work: 32 took 00:00.82
parallel work: 64 took 00:00.80
parallel work: 1k took 00:00.77
parallel work: 10k took 00:00.78
parallel work: 100k took 00:00.77
Parallel là một giải pháp tốt cho multi-Thread và multi-Core, nhưng chúng ta không nên lạm dụng. Hãy hiểu rõ bản chất vấn đề và hiện thực bạn đang đối mặt để chọn gải pháp tốt nhất. Phải chắc chắn rằng bài toán ban đang giải quyết là một bài toán Parallelizable thì mới dùng parallel. Cuối cùng, nên nhớ rằng “đừng lấy dao mổ trâu đi giết gà” và ngược lại. Trên đây là sự hiểu biết cá nhân, rất mong được góp ý.
Phạm Tuân