11 Chủ đề trong C # - Phần 10: BackgroundWorker

(Post 02/11/2007) BackgroundWorker là một lớp trợ giúp trong không gian tên System.ComponentModel để quản lý một luồng công nhân. BackgroundWorker sử dụng nhóm luồng, nhóm này tái chế các luồng để tránh tạo lại chúng cho mỗi tác vụ mới. Điều này có nghĩa là không bao giờ được gọi Abort trên một chuỗi BackgroundWorker.

  • Phần 1: Tổng quan và khái niệm
  • Phần 2: Tạo và bắt đầu chủ đề
  • Phần 3: Cơ bản về đồng bộ hóa
  • Phần 4: Khóa và an toàn chỉ
  • Phần 5: Ngắt và hủy bỏ
  • Phần 6: Trạng thái luồng
  • Phần 7: Xử lý Chờ
  • Phần 8: Bối cảnh đồng bộ hóa
  • Phần 9: Căn hộ và Hình thức Windows

BackgroundWorker là một lớp trợ giúp trong không gian tên System.ComponentModel để quản lý một luồng công nhân. Nó cung cấp các tính năng sau:

  • Cờ “hủy bỏ” để báo hiệu một nhân viên kết thúc mà không sử dụng Hủy bỏ
  • Một giao thức chuẩn để báo cáo tiến độ, hoàn thành và hủy bỏ
  • Việc triển khai IComponent cho phép nó được đặt trong Visual Studio Designer
  • Xử lý ngoại lệ trên chuỗi công nhân
  • Khả năng cập nhật các điều khiển Windows Forms để đáp ứng với tiến độ hoặc quá trình hoàn thành của nhân viên.

Hai tính năng cuối cùng đặc biệt hữu ích – điều đó có nghĩa là bạn không phải bao gồm khối try / catch trong phương thức worker của mình và có thể cập nhật các điều khiển Windows Forms mà không cần gọi Control.Invoke.

BackgroundWorker sử dụng nhóm luồng, nhóm này tái chế các luồng để tránh tạo lại chúng cho mỗi tác vụ mới. Điều này có nghĩa là không bao giờ được gọi Abort trên một chuỗi BackgroundWorker.

Dưới đây là các bước tối thiểu để sử dụng BackgroundWorker:

  • Khởi tạo BackgroundWorker và xử lý sự kiện DoWork
  • Gọi RunWorkerAsync, tùy chọn với đối số đối tượng.

Điều này sau đó đặt nó vào chuyển động. Bất kỳ đối số nào được chuyển đến RunWorkerAsync sẽ được chuyển tiếp đến trình xử lý sự kiện của DoWork, thông qua thuộc tính Argument của đối số sự kiện. Đây là một ví dụ:

class Program {
static BackgroundWorker bw = new BackgroundWorker();
static void Main() {
bw.DoWork += bw_DoWork;
bw.RunWorkerAsync (“Message to worker”);
Console.ReadLine();
}

static void bw_DoWork (object sender, DoWorkEventArgs e) {
// This is called on the worker thread
Console.WriteLine (e.Argument); // writes “Message to worker”
// Perform time-consuming task…
}

BackgroundWorker cũng cung cấp một sự kiện RunWorkerCompleted sẽ kích hoạt sau khi trình xử lý sự kiện DoWork thực hiện xong công việc của nó. Xử lý RunWorkerCompleted là không bắt buộc, nhưng người ta thường làm như vậy để truy vấn bất kỳ ngoại lệ nào được đưa ra trong DoWork. Hơn nữa, mã bên trong trình xử lý sự kiện RunWorkerCompleted có thể cập nhật các điều khiển của Windows Forms mà không cần điều chỉnh rõ ràng; mã bên trong trình xử lý sự kiện DoWork không thể.

Để thêm hỗ trợ cho báo cáo tiến độ:

  • Đặt thuộc tính WorkerReportsProgress thành true
  • Định kỳ gọi ReportProgress từ bên trong trình xử lý sự kiện DoWork với giá trị “phần trăm hoàn thành” và tùy chọn đối tượng trạng thái người dùng
  • Xử lý sự kiện ProgressChanged, xác định thuộc tính ProgressPercentage của đối số sự kiện của nó

Mã trong trình xử lý sự kiện ProgressChanged miễn phí tương tác với các điều khiển giao diện người dùng giống như với RunWorkerCompleted. Đây thường là nơi bạn sẽ cập nhật thanh tiến trình.

Để thêm hỗ trợ cho việc hủy bỏ:

  • Đặt thuộc tính WorkerSupportsCancellation thành true
  • Kiểm tra định kỳ thuộc tính CancelPending từ bên trong trình xử lý sự kiện DoWork – nếu đúng, hãy đặt thuộc tính Cancel của đối số sự kiện là true và trả về. (Nhân viên có thể đặt Cancel true và thoát mà không cần nhắc thông qua CancelPending – nếu công việc đó quyết định công việc quá khó và không thể tiếp tục).
  • Gọi CancelAsync để yêu cầu hủy bỏ.

Dưới đây là một ví dụ triển khai tất cả các tính năng trên:

sử dụng Hệ thống;
sử dụng System.Threading;
sử dụng System.ComponentModel;

Chương trình lớp {
static BackgroundWorker bw;
static void Main () {
bw = new BackgroundWorker ();
bw.WorkerReportsProgress = true;
bw.WorkerSupportsCancellation = true;
bw.DoWork + = bw_DoWork;
bw.ProgressChanged + = bw_ProgressChanged;
bw.RunWorkerCompleted + = bw_RunWorkerCompleted;

bw.RunWorkerAsync (“Xin chào nhân viên”);

Console.WriteLine (“Nhấn Enter trong 5 giây tới để hủy”);
Console.ReadLine ();
if (bw.IsBusy) bw.CancelAsync ();
Console.ReadLine ();
}

static void bw_DoWork (object sender, DoWorkEventArgs e) {
for (int i = 0; i <= 100; i + = 20) {
if (bw.CancellationPending) {
e.Cancel = true;
trở về;
}
bw.ReportProgress (i);
Thread.Sleep (1000);
}
e.Result = 123; // Điều này được chuyển đến RunWorkerCopmleted
}

static void bw_RunWorkerCompleted (object sender,
RunWorkerCompletedEventArgs e) {
if (e.Cancelt)
Console.WriteLine (“Bạn đã hủy!”);
else if (e.Error! = null)
Console.WriteLine (“Ngoại lệ công nhân:” + e.Error.ToString ());
else
Console.WriteLine (“Hoàn thành -” + e.Result); // from DoWork
}

static void bw_ProgressChanged (object sender,
ProgressChangedEventArgs e) {
Console.WriteLine (“Đạt” + e.ProgressPercentage + “%”);
}
}

 

Nhấn Enter trong 5 giây tiếp theo để hủy
Đã đạt 0%
Đã đạt 20%
Đã đạt 40%
Đã đạt 60%
Đã đạt 80%
Đã đạt 100%
Hoàn thành – 123

Nhấn Enter trong 5 giây tiếp theo để hủy
Đã đạt 0%
Đã đạt 20%
Đã đạt 40%

Bạn đã hủy

Nền tảng phân lớp

BackgroundWorker không được niêm phong và cung cấp một phương thức OnDoWork ảo, đề xuất một mẫu khác để sử dụng. Khi viết một phương thức có khả năng chạy lâu, thay vào đó, người ta có thể – hoặc cũng có thể viết một phiên bản trả về một BackgroundWorker phân lớp con, được cấu hình sẵn để thực hiện công việc một cách không đồng bộ. Sau đó, người tiêu dùng chỉ cần xử lý các sự kiện RunWorkerCompleted và ProgressChanged. Ví dụ: giả sử chúng ta đã viết một phương thức tốn thời gian có tên là GetFinancialTotals:

public class Client {
Dictionary<string,int>GetFinancialTotals (int foo, int bar) {…}

}</string,int>

Chúng tôi có thể cấu trúc lại nó như sau:

public class Client {
public FinancialWorker GetFinancialTotalsBackground (int foo, int bar) {
return new FinancialWorker (foo, bar);
}
}

public class FinancialWorker: BackgroundWorker {
public Dictionary<string,int>Kết quả; // Chúng ta có thể thêm các trường đã nhập.
công khai biến động int Foo, Bar; // Chúng tôi thậm chí có thể hiển thị chúng
// thông qua các thuộc tính có khóa!
public FinancialWorker () {
WorkerReportsProgress = true;
WorkerSupportsCancellation = true;
}

public FinancialWorker (int foo, int bar): this () {
this.Foo = foo; this.Bar = thanh;
}

bảo vệ ghi đè void OnDoWork (DoWorkEventArgs e) {
ReportProgress (0, “Làm việc chăm chỉ với báo cáo này …”);
Khởi tạo dữ liệu báo cáo tài chính

while (! Báo cáo hoàn thành) {
if (CancelPending) {
e.Cancel = true;
trở về;
}
Thực hiện một bước tính toán khác
ReportProgress (phần trămCompleteCalc, “Đến đó …”);
}
ReportProgress (100, “Đã xong!”);
e.Result = Kết quả = dữ liệu báo cáo đã hoàn thành;
}
}</string,int>

Bất cứ ai gọi GetFinancialTotalsBackground sau đó sẽ nhận được FinancialWorker – một trình bao bọc để quản lý hoạt động nền với khả năng sử dụng trong thế giới thực. Nó có thể báo cáo tiến độ, bị hủy và tương thích với Windows Forms mà không cần Control.Invoke. Nó cũng được xử lý ngoại lệ và sử dụng một giao thức tiêu chuẩn (chung với giao thức của bất kỳ ai khác sử dụng BackgroundWorker!)

Việc sử dụng BackgroundWorker này sẽ loại bỏ “mẫu không đồng bộ dựa trên sự kiện” cũ một cách hiệu quả.

(Sưu tầm)

FPT Aptech trực thuộc Tổ chức Giáo dục FPT có hơn 25 năm kinh nghiệm đào tạo lập trình viên quốc tế tại Việt Nam, và luôn là sự lựa chọn ưu tiên của các sinh viên và nhà tuyển dụng.
0981578920
icons8-exercise-96