2010-09-16 61 views
5

Mã của tôi chạy 4 chức năng để điền vào thông tin (Sử dụng Invoke) đến một lớp học như:Parallel.Invoke - ngoại lệ xử lý

class Person 
{ 
    int Age; 
    string name; 
    long ID; 
    bool isVegeterian 

    public static Person GetPerson(int LocalID) 
    { 
     Person person; 
     Parallel.Invoke(() => {GetAgeFromWebServiceX(person)}, 
         () => {GetNameFromWebServiceY(person)}, 
         () => {GetIDFromWebServiceZ(person)}, 
         () => 
         { 
          // connect to my database and get information if vegeterian (using LocalID) 
          .... 
          if (!person.isVegetrian) 
           return null 
          .... 
         }); 
    } 
} 

Câu hỏi của tôi là: Tôi không thể trở về null nếu anh ta không phải là một chay, nhưng tôi muốn có thể dừng tất cả các chủ đề, ngừng xử lý và trả về null. Làm thế nào nó có thể đạt được?

Trả lời

4

Vâng, bạn có thể ném ngoại lệ từ hành động của mình, bắt AggregateException trong GetPerson (ví dụ: đặt khối try/catch xung quanh Parallel.Invoke), kiểm tra xem đó có đúng loại ngoại lệ hay không và trả lại giá trị rỗng.

Điều đó đáp ứng mọi thứ ngoại trừ dừng tất cả các chuỗi. Tôi nghĩ rằng bạn không thể dễ dàng có thể dừng các tác vụ đang chạy trừ khi bạn bắt đầu nhận được mã thông báo hủy. Bạn có thể ngừng thêm các tác vụ từ việc thực thi bằng cách giữ giá trị boolean để cho biết liệu bất kỳ tác vụ nào cho đến nay đã thất bại và làm cho mỗi tác vụ kiểm tra trước khi bắt đầu ... nó hơi xấu, nhưng nó sẽ hoạt động.

Tôi nghi ngờ rằng việc sử dụng các tác vụ "đầy đủ" thay vì Parallel.Invoke sẽ làm cho tất cả điều này trở nên thanh lịch hơn.

7

Để thoát khỏi Parallel.Invoke càng sớm càng tốt bạn phải làm ba việc:

  1. Schedule hành động mà phát hiện xem bạn có muốn để thoát sớm hành động đầu tiên. Sau đó nó được lên kế hoạch sớm hơn (có thể là đầu tiên, nhưng điều đó không được bảo đảm) vì vậy bạn sẽ biết sớm hơn cho dù bạn muốn thoát.
  2. Ném ngoại lệ khi bạn phát hiện lỗi và bắt gặp số AggregateException khi câu trả lời của Jon cho biết.
  3. Sử dụng mã thông báo hủy. Tuy nhiên, điều này chỉ có ý nghĩa nếu bạn có cơ hội để kiểm tra tài sản IsCancellationRequested của họ.

Mã của bạn sau đó sẽ trông như sau:

var cts = new CancellationTokenSource(); 
try 
{ 
    Parallel.Invoke(
     new ParallelOptions { CancellationToken = cts.Token }, 
     () => 
     { 
      if (!person.IsVegetarian) 
      { 
       cts.Cancel(); 
       throw new PersonIsNotVegetarianException(); 
      } 
     }, 
     () => { GetAgeFromWebServiceX(person, cts.Token) }, 
     () => { GetNameFromWebServiceY(person, cts.Token) }, 
     () => { GetIDFromWebServiceZ(person, cts.Token) } 
    ); 
} 
catch (AggregateException e) 
{ 
    var cause = e.InnerExceptions[0]; 
    // Check if cause is a PersonIsNotVegetarianException. 
} 

Tuy nhiên, như tôi đã nói, tokens hủy chỉ có ý nghĩa nếu bạn có thể kiểm tra chúng. Vì vậy, nên có một cơ hội bên trong GetAgeFromWebServiceX để kiểm tra mã thông báo hủy và thoát sớm, nếu không, chuyển mã thông báo cho các phương thức này không có ý nghĩa.

1

Chắc chắn bạn cần nạp Person từ cơ sở dữ liệu trước? Vì mã của bạn gọi các dịch vụ Web với một giá trị rỗng.

Nếu logic của bạn thực sự là tuần tự, hãy thực hiện tuần tự và chỉ làm song song những gì có ý nghĩa.