Chuyển đến nội dung chính

Lập trình đa luồng với Task

Bài viết được đăng trên Jou Lập trình
Trong phiên bản .NET framework 4.0, Microsoft đã bổ sung nhiều thư viện hỗ trợ việc xử lý đa luồng (multi-threading), nhằm đơn giản hóa việc lập trình lẫn hiệu suất của chương trình. Trong bài viết này, tôi xin hướng dẫn các bạn sử dụng lớp System.Threading.Task.

Task

Một Task đại diện cho một số công việc cần phải hoàn thành. Các công việc này có thể chạy trong 1 thread riêng hoặc có thể thực thi một cách đồng bộ, và kết quả được chờ đợi trả về ở thread gọi nó.
Task là một lớp trừu tượng, bạn có nhiều kiểm soát hơn là việc sử dụng Thread.
Task cho phép bạn tổ chức công việc một cách linh hoạt. Ví dụ:
·         Định nghĩa các công việc tiếp theo, được làm sau khi 1 task khác kết thúc. Công việc có thể khác khi công việc trước đó thực thi thành công hay thất bại.
·         Nhận được kết quả trả từ một luồng khác.
·         Kiểm soát lỗi tốt hơn.
·         Dễ dàng chờ đợi 1 hay nhiều Task thực thi xong.

Tạo một Task (công việc)

Để tạo 1 Task mà không cần nhận lại kết quả:
Cách 1:
Task.Factory.StartNew(() => DoSomeWork); 
Cách 2:
var action = new Action(DoSomeWork);
var task = new Task(action);
task.Start();

Thực hiện Task liên tiếp

Với Task, bạn có thể chỉ ra 1 công việc thực hiện sau khi một công việc khác hoàn thành (tương tự như Background Worker)

        static void Example2()
        {
            var t1 = new Task(DoOnFirst);
            var t2 = t1.ContinueWith(DoOnSecond);
            t1.Start();
        }
        static void DoOnFirst()
        {
            Console.WriteLine("doing some task {0}", Task.CurrentId);
            Thread.Sleep(3000);
        }
        static void DoOnSecond(Task t)
        {
            Console.WriteLine("task {0} finished", t.Id);
            Console.WriteLine("this task id {0}", Task.CurrentId);
            Console.WriteLine("do some cleanup");
            Thread.Sleep(3000);
        }
Với TaskContinuationOptions, bạn chỉ ra điều kiện để thực hiện công việc tiếp theo khi công việc trước đó hoàn thành. Trong ví dụ dưới đây, Task 3 sẽ thực hiện trong trường hợp Task 2 bị lỗi (throw new exception)
        static void Example3()
        {
            var t1 = new Task(DoOnFirst);
            var t2 = t1.ContinueWith(DoOnSecond);
            var t3 = t2.ContinueWith(DoOnThird, TaskContinuationOptions.OnlyOnFaulted);
            t1.Start();
        }
        static void DoOnSecond(Task t)
        {
            Console.WriteLine("task {0} finished", t.Id);
            Console.WriteLine("this task id {0}", Task.CurrentId);
            Console.WriteLine("do some cleanup");
            Thread.Sleep(3000);
            throw new Exception("Failed");
        }
        static  void DoOnThird(Task t)
        {
            Console.WriteLine("task {0} failed", t.Id);
            Console.WriteLine("this task id {0}", Task.CurrentId);
        }
 
Bạn có thể tham khảo thêm TaskContinuationOptions ở trang MSDN

Nhận kết quả trả về từ Task

Để nhận được kết quả trả về từ Task, bạn sử dụng class Task<T> với T là kiểu dữ liệu của kết quả trả về.
Dưới đây là 3 cách gọi hàm:
        static void Example41()
        {
            var task = Task.Factory.StartNew(delegate
            {
                DoSomeWork();
                return 2712;
            });
            Console.WriteLine(task.Result);
        }

        static void Example42()
        {
            var task = Task.Factory.StartNew((Func<int>)DoSomeWork1);
            Console.WriteLine(task.Result);
        }

        static void Example43()
        {
            var task = Task<int>.Factory.StartNew(DoSomeWork1);
            Console.WriteLine(task.Result);
        }

        static int DoSomeWork1()
        {
            DoSomeWork();
            return 2712;
        }
 Lưu ý: TResult property sẽ khóa luồng gọi Task cho đến khi Task đó thực hiện xong.

Chờ đợi 1 (hoặc nhiều) Task

Để chờ đợi 1 Task hoàn thành, bạn gọi hàm Task.Wait
        static void Example51()
        {
            var task = Task.Factory.StartNew(()=>
            {
                DoSomeWork();
                Console.WriteLine("Complete");
            });
            task.Wait();
        }
Để chờ đợi nhiều Task thực thi xong, bạn gọi hàm Task.WaitAll(Task[]).
        static void Example52()
        {
            var task1 = Task.Factory.StartNew(DoSomeWork);

            var task2 = Task.Factory.StartNew(DoSomeWork);

            Task.WaitAll(task1, task2);
        }
Download ví dụ ở MediaFire

 Kết luận:

Hi vọng với bài viết nhỏ này, bạn nắm được các cách cơ bản để thực thi 1 công việc đa luồng và kiểm soát chúng tốt hơn.
Trong phần tới, tôi sẽ hướng dẫn bạn viết 1 ví dụ thực tế về cách sử dụng Task trong lập trình.
Án Bình Trọng

Nhận xét

Bài đăng phổ biến từ blog này

[ASP.NET MVC] Authentication và Authorize

Một trong những vấn đề bảo mật cơ bản nhất là đảm bảo những người dùng hợp lệ truy cập vào hệ thống. ASP.NET đưa ra 2 khái niệm: Authentication và Authorize Authentication xác nhận bạn là ai. Ví dụ: Bạn có thể đăng nhập vào hệ thống bằng username và password hoặc bằng ssh. Authorization xác nhận những gì bạn có thể làm. Ví dụ: Bạn được phép truy cập vào website, đăng thông tin lên diễn đàn nhưng bạn không được phép truy cập vào trang mod và admin.

ASP.NET MVC: Cơ bản về Validation

Validation (chứng thực) là một tính năng quan trọng trong ASP.NET MVC và được phát triển trong một thời gian dài. Validation vắng mặt trong phiên bản đầu tiên của asp.net mvc và thật khó để tích hợp 1 framework validation của một bên thứ 3 vì không có khả năng mở rộng. ASP.NET MVC2 đã hỗ trợ framework validation do Microsoft phát triển, tên là Data Annotations. Và trong phiên bản 3, framework validation đã hỗ trợ tốt hơn việc xác thực phía máy khách, và đây là một xu hướng của việc phát triển ứng dụng web ngày nay.

Tổng hợp một số kiến thức lập trình về Amibroker

Giới thiệu về Amibroker Amibroker theo developer Tomasz Janeczko được xây dựng dựa trên ngôn ngữ C. Vì vậy bộ code Amibroker Formula Language sử dụng có syntax khá tương đồng với C, ví dụ như câu lệnh #include để import hay cách gói các object, hàm trong các block {} và kết thúc câu lệnh bằng dấu “;”. AFL trong Amibroker là ngôn ngữ xử lý mảng (an array processing language). Nó hoạt động dựa trên các mảng (các dòng/vector) số liệu, khá giống với cách hoạt động của spreadsheet trên excel.