Blog chia sẽ kinh nghiệm lập trình và Technical VN. Nơi mà các bạn có thể học tập và tham khảo về những công nghệ mới nhất hiện nay về .NET
Chủ Nhật, 8 tháng 3, 2015
Hôm nay chúng ta sẽ thử đo xem thời gian query Data của "Foreach vs LinQ vs LinQasParallel" như thế nào. Tôi tạo một tool nhỏ để làm việc này.
I> Testing
Bài test 1: Tôi tạo một tool với chức năng là tìm trong một List<int> các số chia hết cho 9, tôi dùng thuật toán vét cạn với độ phức tạp là O(n). Các bạn có thể kiểm tra cách tôi làm sau đây
[code language="csharp"]
IList<int> lstData = new List<int>();
private IList<int> GenerateList(Double max)
{
IList<int> result = new List<int>();
var rand = new Random();
for (int i = 0; i < max; i++)
{
var randInt = rand.Next(50000);
result.Add(randInt);
}
return result;
}
// Executing for test
private void CheckingWithLinqAsParallel()
{
var stopwatch = new Stopwatch();
var countResult = new List<int>();
// Begin timing
stopwatch.Start();
countResult = (from itemValue in lstData.AsParallel()
where (CheckingValue(itemValue))
select itemValue).ToList();
// Stop timing
stopwatch.Stop();
// Write result
txtResult.Text = countResult.Count.ToString();
txtTime.Text = stopwatch.ElapsedTicks.ToString();
}
private void CheckingWithLinq()
{
var stopwatch = new Stopwatch();
var countResult = new List<int>();
// Begin timing
stopwatch.Start();
countResult = (from itemValue in lstData
where (CheckingValue(itemValue))
select itemValue).ToList();
// Stop timing
stopwatch.Stop();
// Write result
txtResult.Text = countResult.Count.ToString();
txtTime.Text = stopwatch.ElapsedTicks.ToString();
}
private void CheckingWithForeach()
{
var stopwatch = new Stopwatch();
var countResult = new List<int>();
// Begin timing
stopwatch.Start();
foreach(var itemValue in lstData)
{
if (CheckingValue(itemValue))
{
countResult.Add(itemValue);
}
}
// Stop timing
stopwatch.Stop();
// Write result
txtResult.Text = countResult.Count.ToString();
txtTime.Text = stopwatch.ElapsedTicks.ToString();
}
[/code]
Kết quả test:
[code language="c"]
--------------- O(1000) -----------------
Foreach: Time = 133
Linq: Time = 13246
LinqAsParallel: Time = 69348
--------------- O(900000) -----------------
Foreach: Time = 31887
Linq: Time = 25718
LinqAsParallel: Time = 27008
--------------- O(9000000) -----------------
Foreach: Time = 314022
Linq: Time = 263684
LinqAsParallel: Time = 265144
LinqAsParallel: Time = 302023
LinqAsParallel: Time = 264581
Linq: Time = 259860
Linq: Time = 261858
--------------- O(90000000) -----------------
Foreach: Time = 3361146
Linq: Time = 2707332
LinqAsParallel: Time = 2717361
LinqAsParallel: Time = 3562806
LinqAsParallel: Time = 3608036
Linq: Time = 2751347
LinqAsParallel: Time = 2726033
[/code]
Tạm luận: Chúng ta có thể thấy rằng xét về mặt thời gian
- Khi lượng dữ liệu nhỏ và vừa thì Foreach trội hơn nhiều so với LinQ và LinQAsParallel
- Khi lượng dữ liệu lớn dần chạm một ngưỡng nào đó thì Foreach xuống dần phong độ so với LinQ và LinQAsParallel, dữ liệu càng tăng Foreach càng chậm.
- Giữa LinQ và LinQAsParallel, khi Parallel làm việc, nó phụ thuộc nhiều vào sự nhàn rỗi của CPU vì vậy tốc độ không ổn định, khi dữ liệu quá nhỏ Parallel trở nên chậm đáng kể, khi dữ liệu vừa phải Parallel trở nên rất nhanh - vừa phải ở đây phụ thuộc vào khả năng cung ứng Thread của CPU, khi dữ liệu tăng cao, vượt quá lượng Thread mà CPU hiện tại có thể cung cấp - Parallel trở nên chậm lại(Chú ý rằng công việc này là cần sự đồng bộ data).
Bài test 2: Độ phức tạp được nâng lên O(500^n) tức có hai vòng for lòng nhau, 500 là số lần lập cho vòng for trong, tôi không thể test với dữ liệu lớn đáng kể vì sẽ bị ERROR "out of memmory", lượng RAM mà tool chiếm > 2.2GB
[code language="csharp"]
IDictionary<int, IList<int>> lstDataUP = new Dictionary<int, IList<int>>();
private Dictionary<int, IList<int>> GenerateListUP(Double max)
{
var result = new Dictionary<int, IList<int>>();
var rand = new Random();
for (int i = 0; i < max; i++)
{
IList<int> subresult = new List<int>();
for (int j = 0; j < maxsubItem; j++)
{
var randInt = rand.Next(500);
subresult.Add(randInt);
}
result.Add(i,subresult);
}
return result;
}
// Excuteing for test
private void CheckingWithLinqAsParallelUP()
{
var stopwatch = new Stopwatch();
var countResult = new List<int>();
// Begin timing
stopwatch.Start();
countResult = (from itemValue in lstDataUP.AsParallel()
from subitemValue in itemValue.Value.AsParallel()
where (CheckingValue(subitemValue))
select subitemValue).ToList();
// Stop timing
stopwatch.Stop();
txtResult.Text = countResult.Count.ToString();
// Write result
txtTime.Text = stopwatch.ElapsedTicks.ToString();
}
private void CheckingWithLinqUP()
{
var stopwatch = new Stopwatch();
var countResult = new List<int>();
// Begin timing
stopwatch.Start();
countResult = (from itemValue in lstDataUP
from subitemValue in itemValue.Value
where (CheckingValue(subitemValue))
select subitemValue).ToList();
// Stop timing
stopwatch.Stop();
txtResult.Text = countResult.Count.ToString();
// Write result
txtTime.Text = stopwatch.ElapsedTicks.ToString();
}
private void CheckingWithForeachUP()
{
var stopwatch = new Stopwatch();
var countResult = new List<int>();
// Begin timing
stopwatch.Start();
foreach (var itemValue in lstDataUP)
{
foreach (var subitemValue in itemValue.Value)
{
if (CheckingValue(subitemValue))
{
countResult.Add(subitemValue);
}
}
}
// Stop timing
stopwatch.Stop();
txtResult.Text = countResult.Count.ToString();
// Write result
txtTime.Text = stopwatch.ElapsedTicks.ToString();
}
[/code]
Kết quả test
[code language="c"]
--------------- O(500^1000) -----------------
Foreach: Time = 99412
Linq: Time = 1085896
LinqAsParallel: Time = 3105398
--------------- O(500^9000) -----------------
Foreach: Time = 202546
Linq: Time = 695352
LinqAsParallel: Time = 582843
--------------- O(500^90000) -----------------
Foreach: Time = 1605131
Linq: Time = 5647985
LinqAsParallel: Time = 4189570
--------------- O(500^100000) -----------------
Foreach: Time = 1784048
Linq: Time = 6613424
LinqAsParallel: Time = 4496013
--------------- O(500^500000) -----------------
Foreach: Time = 9376404
Linq: Time = 32156749
LinqAsParallel: Time = 22864588
[/code]
Tạm luận: qua bài test trên chúng ta thấy rằng
- Foreach luôn chiếm ưu thế trong tình huống này, dữ liệu càng lớn sự chênh lệch càng rõ
- Giữa LinQ và LinQAsParallel, khi dữ liệu lớn đến một mốc nào đó LinQAsParallel tỏ ra nhanh hơn và ngược lại
- Khi chúng ta quan tâm đến một vài điều kiện để cho phép vòng for con thực thi hoặc không thì sự chênh lệch giữa LinQ và LinQAsParallel càng xa
II> Kết luận
Như vậy, chúng ta có thể tạm kết luận rằng LinQ nhanh hơn hẳn Foreach nếu dữ liệu lớn đáng kể(> trăm ngàn dòng) và độ phức tạp tương đương O(n), nó thật sự chậm chạp khi dữ liệu là nhỏ ở mức vài ngàn dòng; trong khi đó nếu độ phức tạp tăng lên LinQ không phải là một sự lựu chọn tối ưu về tốc độ nếu đứng cạnh Foreach. Hãy cân nhắc đến việc sử dụng LinQ thay cho LinQAsParallel vì Parallel là một con dao hai lưỡi nếu chúng ta không hiểu hết thực trạng hệ thống và khả năng hiện tại của CPU cũng như lượng dữ liệu không cố định. Trong một số trường hợp chúng ta dùng Parallel sẽ bị Exception vì dữ liệu quá lớn trong khi Data cần thiết phải đồng bộ.
Các bài test được thực hiện trên Lap HP probook, I3 và 4G RAM, tình trạng sử dụng tài nguyên không nhiều.
Trên đây là những đánh giá chủ quan về mặt Query data(có đồng bộ) trong một dữ liệu dạng danh sách, tốc độ phụ thuộc nhiều vào thiết kế phần cứng của máy vì vậy hãy tham khảo các kết luận trên như một ý kiến cá nhân, các bạn có thể Comment để thảo luận về đề tài này.
Download SourceCode tại đây, chúc các bạn thành công!
Phạm Tuân
Search
Popular Posts
-
Phong cách thiết kế Material Design nhắm đến những đường nét đơn giản, sử dụng nhiều mảng màu đậm nổi bật, các đối tượng đồ họa trong giao ...
-
Hôm nay tôi sẽ giới thiệu với các bạn một Framework đến từ Microsoft - framework này không quá lớn nhưng là khá mạnh khi các bạn làm việc vớ...
-
WPF vượt trội hơn Winform về khoản Drawing , trong đó đặc biệt WPF hỗ trợ đồ họa rất tốt vì nó tương tác trực tiếp đến GPU. Hôm nay chúng t...
-
Hôm nay chúng ta sẽ tìm hiểu cách tạo ra các menu chuột phải trên ứng dụng WPF của mình. Ở bài này chúng ta xoay quanh việc tìm hiểu cách tạ...
-
Để dễ hiểu, các bạn hãy hình dung rằng: cùng một tập tin thực thi *.EXE nhưng bạn DoubleClick 10 lần cách quãng vào nó thì chuyện gì sẽ sảy ...
-
Trong bài viết trước tôi có giới thiệu về Extension Methods trong nguôn ngữ lập trình C#; hôm nay tôi sẽ nói về một vấn đề có ý nghĩa tương...
-
Hôm nay chúng ta sẽ thử đo xem thời gian query Data của "Foreach vs LinQ vs LinQasParallel" như thế nào. Tôi tạo một tool nhỏ để l...
-
Data Binding là kĩ thuật dùng để tạo gắn kết giữa phần giao diện ( UI ) và dữ liệu thông qua phần business logic hoặc giữa các đối tượng UI...
-
LOG4NET là một thư viện mã nguồn mở cho phép chúng ta tạo ra một hoặc nhiều tập tin log, kiểu log cũng như nội dung log một cách linh hoạt v...
-
Sau hai bài giới thiệu về Caliburn.Micro framework, hôm nay chúng ta sẽ cùng bắt tay vào làm một dự án nhỏ - HelloWorld. Step 1: Add referen...
Recent Posts
Blog Archive
-
▼
2015
(48)
-
▼
tháng 3
(12)
- WPF Training - Drag and Drop Trong WPF Part I
- C# - Khi Nào Nên Dùng Lớp Parallel
- WPF - Xây Dựng Ứng Dụng WPF Metro Với Thư Viện Mah...
- WPF Styles - ToggleButton Switch Phong Cách IOS
- C# - Tìm Hiểu Về MEF Trong Lập Trình C#
- C# - Kiểm Tra Tốc Độ Của Foreach vs LinQ vs LinQas...
- WPF vs Caliburn - IoC Là Gì Và Cấu Hình Bootstrapp...
- WPF vs Caliburn - Bắt Đầu HelloWorld Project Cùng ...
- WPF vs Caliburn- Tìm Hiểu Về Caliburn.Micro Framew...
- WPF vs Caliburn- Tìm Hiểu Về Caliburn.Micro Framew...
- Log4net - Configuration log4net Nâng Cao (các filt...
- WPF Training - How To Binding RadioButton Group
-
▼
tháng 3
(12)


0 nhận xét:
Đăng nhận xét