Xử lý đồng bộ Thread với Async và Await trong C#

Trong bài viết sẽ đề cập đến vấn đề sử dụng từ khóa async và await giúp developer có thể tiếp cận và vận dụng tốt nhất tính năng này của WinRT.

WinRT được xây dựng dựa trên sự chú trọng về xử lí asynchoronous (tạm dịch là không đồng bộ) của các tiến trình, đó là điểm nhấn đáng chú ý của WinRT, bằng việc phân luồng xử lí và sắp xếp các luồng một cách hợp lí nhất, giúp WinRT ngày càng chiếm lấy cảm tình của người dùng, bởi lẽ cách xử lí ít tốn time của CPU, khá mượt mà và dễ chịu của nó.

Như đề cập ở tiêu đề, khác Synchoronous (đồng bộ hóa), Asynchoronous cho phép chương trình thực hiện các công việc khác trong khi chờ Task thực hiện.



Xét ví dụ bằng lập trình C# dưới đây:

protected void btnSubmit_Click(object sender, RoutedEventArgs e) 

     { 

       int res = 0; 

       var task = ThreadPool.RunAsync(delegate { res = DoSomeThing(); }); 

       task.Completed = delegate(IAsyncAction asyncAction, AsyncStatus asyncStatus) 

       { 

         btnSubmit.Content = res.ToString();  //lỗi

       } 

     } 

Ví dụ trên thực hiện một công việc đơn giản: tạo một Thread nằm trong ThreadPool sau đó thực hiện hàm DoSomeThing() trả giá trị trở về cho res, sau khi công việc hoàn tất, gán giá trị của res trở về cho btnSubmit.Content (Ví dụ thường thấy trong thao tác Client để chờ trả lời từ Server hoặc Webservices) . Tuy nhiên:

+ không phải lúc nào hàm DoSomeThing() cũng có giá trị đúng đắn.

+ Trong lúc tạo CallBack cho task ta đã sinh ra một Thread ko thuộc UI, không thể thay đổi giá trị của các UI (button)

Khi đó:

+ AsyncStatus cung cấp các giá trị cho biết kết quả của quá trình thực hiện.

+ Đưa đoạn xử lý vào UI Thread.

Ta có đoạn code dưới đây:

protected void btnSubmit_Click(object sender, RoutedEventArgs e) 

  { 

    int res = 0; 

    var task = ThreadPool.RunAsync(delegate { res = DoSomeThing(); }); 

    task.Completed = delegate(IAsyncAction asyncAction, AsyncStatus asyncStatus) 

    { 

        Dispatcher.RunAsync(CoreDispatcherPriority.Normal, delegate

        { 

          switch (asyncStatus) 

          { 

            case AsyncStatus.Completed: 

              btnSubmit.Content = res.ToString(); 

              break; 

            case AsyncStatus.Error: 

              btnSubmit.Content = asyncAction.ErrorCode.Message;  

              break; 

            case AsyncStatus.Canceled: 

              btnSubmit.Content = "A task was stupid"; 

              break; 

          } 

        }); 

    } 

  } 

CoreDispatcher gắn kết thao tác xử lí vào UI, từ đó cho phép thao tác với UI. asyncStatus cho phép ta xác định kết quả thực hiện của thread bao gồm Cancelled, Complete, Error.

Việc thao tác như trên gây nhiều phiền toái và khá "cơ bắp", khiến cho việc xử lí trở nên rườm rà phức tạp. Đối với WinRT ta có thể thao tác đơn giản như sau:

protected async void btnSubmit_Click(object sender, RoutedEventArgs e) 

     { 

       try

       {

          int res = 0;  //(1)

          await ThreadPool.RunAsync(delegate { res = DoSomeThing(); });  //(2)

          btnSubmit.Content = res.ToString();     //(3)

       }

        catch {}

     }  

Trong đoạn code trên, sau khi thực hiện dòng lệnh (1), ThreadPool tạo và thực thi tìm giá trị của res thông qua hàm DoSomeThing(). sau đó đợi đến khi quá trình kết thúc thì gán giá trị cho Content

Mặt khác, nếu muốn trả về giá trị của một Task được gọi thực thi, WinRT cung cấp bộ chuyển dử liệu với từ khóa Task. ta xét ví dụ dưới đây.

protected async Task<int> DoSomeThing() 

     { 

       int res = await GetInformation("http://localhost/customerID"); 

       return res; 

     }  </int>

Theo dõi http://laptrinhtot.com để tiếp tục theo dõi các loạt bài mới nhất về C# nhé!

Tags: