2013-06-14 45 views
6

Tôi đang cố gắng sử dụng xử lý song song để tăng tốc một vài vòng lồng nhau, nhưng tôi gặp sự cố khi nhận cú pháp đúng. Tôi đang cố gắng để có được một số lượng bao nhiêu điểm ảnh trong một bitmap là màu đỏ, trắng, hoặc đen, các giá trị mà tôi có trong một enum ở nơi khác.Song song Đối với vòng lặp trong C# với biến được chia sẻ

Trong xử lý nối tiếp tôi đã đoạn mã sau, trong đó hoạt động tốt:

 Bitmap image = new Bitmap(@"Input.png"); 
     var colourCount = new int[3]; 

     for (var x = 0; x < image.Width; x++) 
     { 
      for (var y = 0; y < image.Height; y++) 
      { 
       switch (image.GetPixel(x, y).ToArgb()) 
       { 
        case (int)colours.red: colourCount[0]++; break; 
        case (int)colours.white: colourCount[1]++; break; 
        case (int)colours.black: colourCount[2]++; break; 
        default: throw new ArgumentOutOfRangeException(string.Format("Unexpected colour found: '{0}'", image.GetPixel(x, y).ToArgb())); 
       } 
      } 
     } 

Tôi đã nhìn thấy mã cho song song cho vòng bởi Microsoft và từ Stackoverflow đó cập nhật một biến được chia sẻ như sau:

 Parallel.For<int>(0, result.Count,() => 0, (i, loop, subtotal) => 
     { 
      subtotal += result[i]; 
      return subtotal; 
     }, 
      (x) => Interlocked.Add(ref sum, x) 
     ); 

Nhưng tất cả các ví dụ đều sử dụng một kiểu đơn giản như int như biến chia sẻ và tôi không thể tìm ra cú pháp để ghi vào mảng ba kích thước của mình. Tôi có tiếp cận điều này không?

Bằng cách này, tôi biết về hiệu suất mà GetPixel là rất chậm so với một cái gì đó như Bitmap.LockBits, tôi chỉ cố gắng để có được nguyên tắc của vòng lặp song song đúng.

Trả lời

4

Bạn có thể sử dụng quá tải Parallel.For cho phép bạn duy trì trạng thái địa chỉ luồng. Trong trường hợp này, chúng ta tạo một mảng int[3] cho mỗi luồng được sinh ra. Trong mỗi vòng lặp của vòng lặp song song, chúng tôi chỉ cập nhật mảng cục bộ, localColourCount. Cuối cùng, khi chuỗi được gỡ bỏ, chúng tôi tổng hợp các kết quả của từng mảng cục bộ vào chuỗi tổng thể, colourCount; tuy nhiên, vì đây là cấu trúc dữ liệu được chia sẻ, chúng tôi thực thi loại trừ lẫn nhau trong khi truy cập nó.

Bitmap image = new Bitmap(@"Input.png"); 
var colourCount = new int[3]; 

Parallel.For(0, image.Width, 

    // localInit: The function delegate that returns the initial state 
    //   of the local data for each task. 
    () => new int[3], 

    // body: The delegate that is invoked once per iteration. 
    (int x, ParallelLoopState state, int[] localColourCount) => 
    { 
     for (var y = 0; y < image.Height; y++) 
     { 
      switch (image.GetPixel(x, y).ToArgb()) 
      { 
       case (int)colours.red: localColourCount[0]++; break; 
       case (int)colours.white: localColourCount[1]++; break; 
       case (int)colours.black: localColourCount[2]++; break; 
       default: throw new ArgumentOutOfRangeException(
          string.Format("Unexpected colour found: '{0}'", 
          image.GetPixel(x, y).ToArgb())); 
      } 
     } 
    }, 

    // localFinally: The delegate that performs a final action 
    //    on the local state of each task. 
    (int[] localColourCount) => 
    { 
     // Accessing shared variable; synchronize access. 
     lock (colourCount) 
     { 
      for (int i = 0; i < 3; ++i) 
       colourCount[i] += localColourCount[i]; 
     } 
    }); 

Mã này giả định rằng Bitmap.GetPixel là an toàn chủ đề, có thể xảy ra hoặc không.

Một điều bạn cần chú ý là bất kỳ trường hợp ArgumentOutOfRangeException nào sẽ được kết hợp thành một số AggregateException, vì vậy, bạn sẽ cần điều chỉnh mã xử lý lỗi của mình.

+0

Bạn thực sự không cần 'khóa' trong' localFinally'. Thay vào đó bạn có thể sử dụng 'Interlocked.Add()' trong vòng lặp của bạn. Mặc dù sử dụng 'khóa' làm cho nó rõ ràng là chính xác hơn. – svick

+0

@svick: Nhiều lời gọi của 'Interlocked.Add' có thể kém hiệu quả hơn một' khóa' duy nhất. (Chắc chắn là trường hợp nếu 'colourCount' bao gồm hàng chục phần tử, không chắc chắn cho 3.) Mỗi ​​[Albahari] (http://www.albahari.com/threading/part4.aspx):" Tất cả các 'khóa liên động ''s phương pháp tạo ra một hàng rào đầy đủ." Khoản phí vô hiệu hóa bộ nhớ cache lặp lại có thể vượt quá chi phí của khóa đơn. – Douglas

+0

Cảm ơn bạn đã đăng bài, điều đó có ý nghĩa hơn với tôi bây giờ. Bạn đúng khi gợi ý rằng GetPixel không phải là chủ đề an toàn, trên thực tế việc truy cập bất kỳ thuộc tính hoặc phương thức hình ảnh nào có vẻ là không có, vì vậy tôi sẽ phải tìm ra cách làm tròn, nhưng tôi đã có vòng lặp chính nó làm việc tốt. Cảm ơn một lần nữa! –

Các vấn đề liên quan