Lưu Quang Triệu

Không ngừng sáng tạo thì sẽ không sợ bị diệt vong

Lập trình đa luồng với C# 4.0

Posted by millionking on August 10, 2012

Từ khi ra đời với phiên bản 1.0 đến nay, C# không ngừng được cải tiến với nhiều tính năng mạnh mẽ. C# 3.0 nổi bật với những cú pháp mở rộng để hỗ trợ LINQ. Trong khi đó, C# 4.0 chú trọng nhiều đến lập trình đa luồng và lập trình động (dynamic programming). Bài viết này trình bày tổng quan về những điểm mới trong lập trình đa luồng với C# 4.

1. Lớp Task:
Lớp Task đơn giản hóa đáng kể việc sử dụng CLR Thread pool, thậm chí còn có thể giúp gia tăng tốc độ. Đó là nhờ bản hiện thực của lớp Task đã tận dụng các kĩ thuật đồng bộ không cần khóa (lock-free) để giảm tối đa số khóa trong chương trình. Sử dụng lớp Task đơn giản như sau:

Task myTask = Task.Factory.StartNew(() => {
// do something here
});

Phương thức StartNew() nhận vào một delegate không có tham số và không trả trị (ví dụ trên dùng cú pháp của toán tử lambda). Delegate này sau đó sẽ được thực thi trong một luồng riêng. Ngoài ra lớp Task còn có một số phương thức như ContinueWith() để thực hiện nhiều tác vụ nối tiếp nhau. Trong trường hợp đó, đoạn code thường được đặt trong khối try…catch:

try
{
Task myTask = Task.Factory.StartNew(() => {
// do something here

myTask.ContinueWith(() => {
// …
}
});
}
catch (AggregateException ex)
{
// do something here
}

Trong trường hợp này, exception có thể phát sinh tại task thứ nhất hoặc task thứ hai (task trong câu lệnh ContinueWith). AggregateException là kiểu exception đặc biệt để bắt một tập hợp các exception có thể xảy ra từ bất cứ task nào.

2. Lớp Parallel:
Lớp Parallel cung cấp các phương thức static cho phép thực hiện một số tác vụ truyền thống theo kiểu song song. Hai phương thức phổ biến nhất là For() và ForEach(), có chức năng như một vòng lặp thông thường nhưng có thể phân hoạch collection thành nhiều phần để xử lý đồng thời. Ví dụ:

int[] numbers = new int[] {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10};
Parallel.For( 0, numbers.Length, (i) =>
{
numbers[i] = number[i] * 2;
Console.WriteLine(numbers[i]);
});

Lưu ý rằng kết quả xuất ra ở mỗi lần chạy có thể khác nhau và không giống với thứ tự ban đầu trong mảng, điều này chứng tỏ các thao tác được thực thi song song. Một điểm chú ý quan trọng khác là tốc độ. Việc thực thi song song không đồng nghĩa với việc gia tăng tốc độ, đặc biệt trong các trường hợp đơn giản như trên. Tốc độ thực thi phụ thuộc vào nhiều yếu tố khác nhau, và đa luồng sẽ hầu như không mang lại cải thiện tốc độ nào trên các hệ thống một bộ xử lý (các hệ thống đa nhân có thể coi như nhiều bộ xử lý). Mặc dù khả năng xử lý song song là rất hấp dẫn, chúng cần tránh bị lạm dụng.

3. Parallel LINQ:
LINQ hay ngôn ngữ truy vấn tích hợp (Language INtegrated Query) là một bổ sung đáng giá của C# 3.0, cho khả năng truy vấn dữ liệu từ nhiều nguồn khác nhau (trên bộ nhớ, trong dataset, file XML hay database) bằng một cú pháp thống nhất. Trong C# 4, LINQ được tăng cường thêm khả năng hỗ trợ đa luồng với toán tử AsParallel(). Toán tử mới này cho phép chuyển câu truy vấn LINQ bình thường thành câu truy vấn song song:

int[] numbers = new int[1000];
/*
initialize here: fill numbers array with values

*/
var result = numbers.AsParallel().Where((i) => i % 2 == 0);

Khi sử dụng toán tử AsParralel() cần lưu ý các vấn đề tương tự như với các phương thức của lớp Parallel.

4. Thread-safe collections:
Vấn đề đồng bộ hóa là một trong những vấn đề phức tạp nhất của lập trình đa luồng. Nhằm giảm bớt gánh nặng cho lập trình viên, .NET Framework 4 cung cấp sẵn các tập hợp an toàn luồng. Đây là các tập hợp được thiết kế để hỗ trợ việc truy vấn đồng thời từ nhiều luồng khác nhau. Ngoài việc đơn giản hóa đáng kể các thao tác với dữ liệu, các tập hợp này còn được tối ưu về mặt tốc độ với việc áp dụng các kĩ thuật đồng bộ lock-free. NET Framework 4 đi kèm theo các thread-safe collection sau: ConcurrentQueue, ConcurrentBag, ConcurrentStack, ConcurrentDictionary. Các tập hợp này có các phương thức cho phép thêm, xóa và lặp qua các phần tử trong môi trường đa luồng một cách an toàn và hiệu quả. Đây là các công cụ hữu ích mà lập trình viên nên tìm hiểu sử dụng để tiết kiệm thời gian và công sức.

Kết luận:
Lập trình đa luồng là một đề tài lớn và phức tạp. Trong khuôn khổ giới hạn, bài viết chỉ trình bày về những nét mới mà C# 4.0 đem lại, hi vọng ít nhiều sẽ giúp ích cho các lập trình viên phải thường xuyên đối mặt với công việc rắc rối nhưng đầy thú vị này.

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s

 
%d bloggers like this: