2011-07-12 27 views
6

Tôi có một ứng dụng hoạt động tuyệt vời để xử lý các tệp nằm trong một thư mục trên máy chủ của tôi. Quá trình này là:Xử lý đồng thời các tệp khi chúng đến trong C#

1) check for files in a directory 
2) queue a user work item to handle each file in the background 
3) wait until all workers have completed 
4) goto 1 

này hoạt động độc đáo và tôi không bao giờ lo lắng về cùng một tập tin đang được xử lý hai lần hoặc nhiều chủ đề được sinh ra cho cùng một tập tin. Tuy nhiên, nếu có một tệp mất quá nhiều thời gian để xử lý, bướC# 3 sẽ treo trên một tệp đó và giữ tất cả các quá trình xử lý khác. Vì vậy, câu hỏi của tôi là, mô hình chính xác để sinh ra chính xác một luồng cho mỗi tệp mà tôi cần xử lý là gì, trong khi không chặn nếu một tệp mất quá nhiều thời gian? Tôi coi FileSystemWatcher, nhưng các tập tin có thể không đọc được ngay lập tức đó là lý do tại sao tôi liên tục xem tất cả các tệp và tạo ra một tiến trình cho mỗi tệp (sẽ ngay lập tức thoát nếu tệp bị khóa).

Tôi có nên xóa bướC# 3 và duy trì danh sách các tệp tôi đã xử lý không? Điều đó có vẻ lộn xộn và danh sách sẽ phát triển rất lớn theo thời gian vì vậy tôi nghi ngờ có một giải pháp thanh lịch hơn.

+0

Điều gì xảy ra với một tệp sau khi tệp được xử lý? nó vẫn còn trong cùng một thư mục? đã xóa? di chuyển? Ngoài ra, các tệp được bán vào thư mục máy chủ có được đặt tên nhất quán với cùng một phần mở rộng không? – gangelo

+0

Tôi không hiểu quy trình của bạn như được liệt kê ở trên ngăn các tệp được xử lý hai lần như thế nào. –

+0

Sau khi tệp được xử lý, nó bị xóa ở bướC# 2 vì vậy đó là lý do sau khi bướC# 3 hoàn thành, mọi tệp trong thư mục sẽ được xử lý và chưa được xử lý trước đó. – powlette

Trả lời

6

Tôi khuyên bạn nên duy trì danh sách các tệp bạn hiện đang xử lý. Xóa chuỗi khỏi danh sách này khi chuỗi kết thúc. Khi tìm kiếm tệp mới, hãy loại trừ các tệp đó trong danh sách hiện đang chạy.

+0

Làm cách nào để bạn theo dõi tệp nào đã được xử lý sau khi chúng đã bị xóa khỏi hàng đợi chuỗi? – gangelo

+0

Ông đã có vấn đề đó, vì vậy tôi cho rằng điều này đã được giải quyết bằng, ví dụ, các tập tin bị xóa ở phần cuối của quá trình. –

+0

Vâng, đây thực chất là những gì tôi đang nghĩ - chỉ hy vọng có một mô hình người tiêu dùng sản xuất hiện tại đã được thử và đúng hơn là tự mình cuộn. Cảm ơn. – powlette

3

Di chuyển tệp vào thư mục xử lý trước khi bạn bắt đầu chuỗi. Sau đó, bạn có thể kích hoạt các chủ đề và bất kỳ quản trị viên nào có thể xem nhanh những gì đang diễn ra.

+0

Điều này giả định rằng ông thậm chí có thể làm điều này trên máy chủ, nhưng tôi thích ý tưởng này bởi vì bạn biết những tập tin phải được/đang/đã được xử lý bởi đức hạnh của họ đang ở trong thư mục tương ứng của họ. – gangelo

3

Tạo ra một chuỗi cho mỗi mục để xử lý gần như không bao giờ là cách tiếp cận tốt. Trong trường hợp của bạn khi số lượng tệp sẽ vượt quá hàng trăm một luồng mỗi tệp sẽ làm cho hiệu suất ứng dụng khá tệ và với quy trình 32 bit sẽ bắt đầu chạy hết dung lượng địa chỉ.

Danh sách giải pháp của Dark Falcon đủ đơn giản và phù hợp với thuật toán của bạn. Tôi thực sự sẽ sử dụng hàng đợi (likle ConcurrentQueue - http://msdn.microsoft.com/en-us/library/dd267265.aspx) để đặt các mặt hàng để xử lý trên một mặt (tức là dựa trên quét định kỳ của trình theo dõi tệp) và chọn các mục để xử lý bởi một hoặc nhiều luồng ở phía bên kia. Nói chung, bạn muốn số lượng chủ đề nhỏ hơn (tức là số lượng CPU 1-2x cho tải trọng CPU).

Cũng xem xét sử dụng Thư viện công việc song song (như Parallel.ForEach - http://msdn.microsoft.com/en-us/library/dd989744.aspx) để xử lý nhiều chuỗi.

Để giảm thiểu số lượng tệp cần xử lý, tôi sẽ giữ danh sách các mục đã được xử lý - đường dẫn tệp + ngày sửa đổi cuối cùng (trừ khi bạn có thể lấy thông tin này từ nguồn khác).

1

hai câu hỏi chính của tôi sẽ là:

  1. kích thước của các tập tin là gì?
  2. Tần suất tệp sẽ xuất hiện?

Tùy thuộc vào câu trả lời của bạn ở đó, tôi có thể đi với các thuật toán sản xuất-tiêu dùng sau:

  1. Sử dụng một watcher hệ thống tập tin để thấy rằng có hoạt động trong thư mục bạn đang theo dõi
  2. Khi hoạt động xảy ra, bắt đầu bỏ phiếu "nhẹ"; đó là kiểm tra từng tệp có sẵn để xem liệu tệp đó có bị khóa hay không (tức là, hãy thử mở các đặc quyền w/write bằng cách sử dụng một phương thức mở rộng IsLocked đơn giản để kiểm tra thông qua một lần thử ..bắt lấy); nếu 1 hoặc nhiều tệp không miễn phí, hãy đặt hẹn giờ tắt trong một khoảng thời gian (lâu hơn nếu mong đợi ít tệp lớn hơn, ngắn hơn nếu nhỏ hơn và/hoặc thường xuyên hơn) để kiểm tra lại các tệp
  3. Ngay khi bạn thấy một tập tin là miễn phí, xử lý nó (ví dụ, di chuyển nó vào một thư mục khác, đặt một mục trong một hàng đợi đồng thời, có chủ đề tiêu dùng của bạn xử lý hàng đợi, lưu trữ các tập tin/kết quả).
  4. Có một số loại cơ chế kiên trì như Alexei đề cập (ví dụ: đĩa/cơ sở dữ liệu) để có thể khôi phục việc xử lý của bạn khi bạn rời đi trong trường hợp lỗi hệ thống.

Tôi cảm thấy rằng đây là sự kết hợp tốt giữa hành vi sử dụng CPU không chặn, ít sử dụng CPU. Nhưng đo lường trước và sau kết quả của bạn. Tôi muốn giới thiệu cách sử dụng ThreadPool và cố gắng giữ cho chủ đề từ chặn (ví dụ, hãy thử để đảm bảo chủ đề tái sử dụng bằng cách không chặn bằng cách làm một cái gì đó giống như Thread.Sleep)

Ghi chú:

  1. cơ sở số lượng chủ đề xử lý các tập tin về số lượng CPU và lõi có sẵn trên máy; cũng xem xét tải máy chủ
  2. FileSystemWatcher có thể khó đọc; hãy chắc chắn rằng nó đang chạy từ cùng một máy mà bạn đang giám sát (tức là, không xem máy chủ từ xa), nếu không bạn sẽ cần khởi động lại kết nối theo thời gian.
  3. Tôi chắc chắn sẽ không sinh ra một quy trình khác cho mỗi tệp; nhiều chủ đề nên đủ lớn; sử dụng lại các chủ đề là tốt nhất. Quá trình sinh sản là một hoạt động rất tốn kém và các chủ đề sinh sản là một hoạt động tốn kém. Alexei có một số thông tin tốt về thư viện Task Parallel; nó sử dụng ThreadPool.
Các vấn đề liên quan