2010-02-15 107 views
13

Tôi quan tâm đến việc tìm hiểu về lập trình song song trong C# .NET (không giống như mọi thứ có thể biết, nhưng cơ bản và có thể một số thực hành tốt), do đó tôi đã quyết định lập trình lại chương trình cũ của tôi được gọi là ImageSyncer. ImageSyncer là một chương trình thực sự đơn giản, tất cả những gì bạn cần làm là quét một thư mục và tìm tất cả các tệp kết thúc bằng .jpg, sau đó nó tính toán vị trí mới của các tệp dựa trên ngày chúng được thực hiện (phân tích cú pháp xif-data hoặc bất kỳ thứ gì nó được gọi là). Sau khi một vị trí được tạo ra, chương trình sẽ kiểm tra bất kỳ tệp hiện có nào tại vị trí đó và nếu có tồn tại, nó sẽ xem thời gian ghi cuối cùng của cả tệp để sao chép và tệp "theo cách của nó". Nếu những người bằng nhau thì tập tin bị bỏ qua. Nếu không phải tổng kiểm tra md5 của cả hai tệp được tạo và khớp. Nếu không có tệp trùng khớp nào được sao chép thì phải có một vị trí mới cần sao chép (ví dụ, nếu nó được sao chép vào "C: \ test.jpg" thì nó được sao chép vào "C: \ test (1). jpg "thay vào đó". Kết quả của hoạt động này được điền vào hàng đợi của một kiểu cấu trúc có chứa hai chuỗi, tệp gốc và vị trí để sao chép nó. Sau đó, hàng đợi đó được lặp lại cho đến khi nó trống và các tệp được sao chép.Lập trình song song trong C#

Nói cách khác có 4 hoạt động:

1. Scan directory for jpegs 
2. Parse files for xif and generate copy-location 
3. Check for file existence and if needed generate new path 
4. Copy files 

Và vì vậy tôi muốn viết lại chương trình này để làm cho nó song song và có thể thực hiện một số các hoạt động cùng một lúc, và tôi đã tự hỏi những gì cách tốt nhất để đạt được điều đó. Tôi đã nghĩ ra hai mô hình khác nhau mà tôi có thể nghĩ đến, nhưng không phải một trong số đó có thể là một điều tốt. Đầu tiên là để song song với 4 bước của chương trình cũ, để khi bước một được thực hiện nó được thực hiện trên một số chủ đề, và khi toàn bộ bước 1 là kết thúc bước 2 được bắt đầu. Một cái khác (mà tôi thấy thú vị hơn bởi vì tôi không biết làm thế nào để làm điều đó) là tạo ra một loại công nhân và mô hình người tiêu dùng, vì vậy khi một luồng được hoàn thành với bước 1, một cái khác tiếp quản và thực hiện bước 2 tại đó đối tượng (hoặc một cái gì đó như thế). Nhưng như đã nói, tôi không biết nếu có bất kỳ giải pháp tốt nào. Ngoài ra, tôi không biết nhiều về lập trình song song. Tôi biết cách tạo một chuỗi và cách làm cho nó thực hiện một chức năng tham gia một đối tượng làm tham số duy nhất của nó, và tôi cũng đã sử dụng lớp BackgroundWorker trong một dịp, nhưng tôi không quen thuộc với bất kỳ thứ gì trong số chúng .

Bất kỳ đầu vào nào cũng sẽ được đánh giá cao.

+9

này nghe có vẻ giống như một nhiệm vụ thú vị, nhưng vì nó có khả năng là IO ràng buộc, nhiều chủ đề tất cả đập đi vào đĩa sẽ rất có khả năng làm cho chương trình chạy _slower_ hơn nếu bạn chỉ sử dụng một sợi. –

+0

Thanx, tôi đã không thực sự xem xét điều này. Nhưng tôi nghĩ rằng ít nhất bước 2 và 3 có thể được hưởng lợi từ việc sử dụng một số chủ đề, bạn sẽ không đồng ý? – Alxandr

+0

http://messagingbus.codeplex.com/ có thể giúp –

Trả lời

2

Đây là tài liệu tham khảo tôi sử dụng cho C# chủ đề: http://www.albahari.com/threading/

Là một đơn PDF: http://www.albahari.com/threading/threading.pdf

Đối với phương pháp thứ hai của bạn:

tôi đã làm việc trên một số ứng dụng sản xuất/tiêu dùng đa luồng trong đó mỗi nhiệm vụ là một số mã mà vòng fo r bao giờ hết.Một "bộ khởi tạo" bên ngoài bắt đầu một chuỗi riêng biệt cho mỗi tác vụ và khởi tạo một EventWaitHandle cho mỗi tác vụ. Đối với mỗi tác vụ là một hàng đợi toàn cầu có thể được sử dụng để tạo/tiêu thụ đầu vào.

Trong trường hợp của bạn, chương trình bên ngoài của bạn sẽ thêm từng thư mục vào hàng đợi cho Task1 và Đặt EventWaitHandler cho Task1. Nhiệm vụ 1 sẽ "thức dậy" từ EventWaitHandler của nó, nhận số lượng thư mục trong hàng đợi của nó, và sau đó trong khi số đếm lớn hơn 0, lấy thư mục từ hàng đợi, quét tất cả các tệp .jpgs và thêm từng vị trí .jpg đến một hàng đợi thứ hai, và đặt EventWaitHandle cho nhiệm vụ 2. Nhiệm vụ 2 đọc đầu vào của nó, xử lý nó, chuyển tiếp nó đến một hàng đợi cho nhiệm vụ 3 ...

Nó có thể là một chút đau đớn nhận được tất cả các khóa để làm việc đúng (tôi về cơ bản khóa bất kỳ truy cập vào hàng đợi, thậm chí một cái gì đó đơn giản như nhận được số của nó). .NET 4.0 được cho là có cấu trúc dữ liệu sẽ tự động hỗ trợ hàng đợi của nhà sản xuất/người tiêu dùng không có khóa.

1

Sự cố thú vị. Tôi đã đưa ra hai cách tiếp cận. Việc đầu tiên được dựa trên PLinq và thứ hai là dựa trên te Rx Framework.

Người đầu tiên lặp lại thông qua các tệp song song. Thứ hai tạo ra các tệp không đồng bộ từ thư mục.

Sau đây là cách nó trông giống như trong một phiên bản đơn giản hơn nhiều (Phương pháp đầu tiên không đòi hỏi Net 4.0 vì nó sử dụng PLINQ)

string direcory = "Mydirectory"; 
    var jpegFiles = System.IO.Directory.EnumerateFiles(direcory,"*.jpg"); 


    // -- PLinq -------------------------------------------- 
    jpegFiles 
    .AsParallel() 
    .Select(imageFile => new {OldLocation = imageFile, NewLocation = GenerateCopyLocation(imageFile) }) 
    .Do(fileInfo => 
     { 
      if (!File.Exists(fileInfo.NewLocation) || 
       (File.GetCreationTime(fileInfo.NewLocation)) != (File.GetCreationTime(fileInfo.NewLocation))) 
       File.Copy(fileInfo.OldLocation,fileInfo.NewLocation); 
     }) 
    .Run(); 

    // ----------------------------------------------------- 


    //-- Rx Framework --------------------------------------------- 
    var resetEvent = new AutoResetEvent(false); 
    var doTheWork = 
    jpegFiles.ToObservable() 
    .Select(imageFile => new {OldLocation = imageFile, NewLocation = GenerateCopyLocation(imageFile) }) 
    .Subscribe(fileInfo => 
     { 
      if (!File.Exists(fileInfo.NewLocation) || 
       (File.GetCreationTime(fileInfo.NewLocation)) != (File.GetCreationTime(fileInfo.NewLocation))) 
      File.Copy(fileInfo.OldLocation,fileInfo.NewLocation); 
     },() => resetEvent.Set()); 

    resetEvent.WaitOne(); 
    doTheWork.Dispose(); 

    // ----------------------------------------------------- 
+0

PLinq yêu cầu .net 4.0, đúng không? – Alxandr

+0

Có yêu cầu .Net 4.0 –

+0

+1 để đề cập và cung cấp một ví dụ cho phương pháp "Rx". –