2011-07-12 32 views
6

我有一個應用程序,非常適合處理文件,在我的服務器上的目錄着陸。這個過程是:同時處理文件,因爲他們到達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 

這工作得很好,我從來不擔心同一個文件被處理兩次或正在醞釀了同一文件的多個線程。但是,如果有一個文件需要很長時間才能處理,則步驟#3將掛起該文件並阻止所有其他處理。

所以我的問題是,什麼是正確的範例,爲我需要處理的每個文件準確地產生一個線程,而如果一個文件需要太長時間沒有阻塞,我考慮過FileSystemWatcher,但這些文件可能無法立即讀取,這就是爲什麼我不斷查看所有文件併爲每個文件產生一個進程(如果文件被鎖定,這些進程會立即退出)。

我應該刪除第3步並保留已處理的文件列表嗎?這似乎很混亂,隨着時間的推移,名單會變得非常大,所以我懷疑有更優雅的解決方案。

+0

文件處理後會發生什麼?它保持在同一個目錄中嗎?刪除嗎?感動?另外,這些文件是否被轉儲到與相同擴展名一致的服務器目錄中? – gangelo

+0

我不明白上面列出的過程如何防止文件被處理兩次。 –

+0

處理文件後,它在步驟#2中被刪除,這就是爲什麼在步驟#3完成之後,文件夾中的任何文件都將被處理並且之前未被處理的原因。 – powlette

回答

6

我建議你維護一個你正在處理的文件列表。當線程結束時,線程從列表中移除。查找新文件時,請排除當前正在運行的列表中的文件。

+0

如何跟蹤哪些文件在從線程隊列中移除後已經被處理? – gangelo

+0

他已經有這個問題,所以我認爲這已經解決了,例如,在該過程結束時被刪除的文件。 –

+0

是的,這實際上就是我在想什麼 - 只是希望有一個現存的生產者 - 消費者範例,這個範例經過了嘗試,而不是自己碾壓。謝謝。 – powlette

3

在啓動線程之前將文件移動到處理目錄。然後,您可以啓動並忘記線程,任何管理員都可以一目瞭然地看到發生了什麼。

+0

這假設他甚至可以在服務器上這樣做,但是我喜歡這個想法,因爲你知道哪些文件必須被處理,因爲它們位於它們各自的目錄中。 – gangelo

3

產生一個線程每個項目處理幾乎從來沒有好辦法。在你的情況下,當文件數量超過幾百個單線程每文件將使應用程序性能非常差,32位進程將開始用盡地址空間。

Dark Falcon的列表解決方案非常簡單,並且與您的算法相匹配。我實際上會使用隊列(比如ConcurrentQueue - http://msdn.microsoft.com/en-us/library/dd267265.aspx)將項目放在一邊(即基於文件觀察者的週期性掃描)並選擇要由另一邊的一個或多個線程處理的項目。您通常需要較少數量的線程(即CPU密集型負載的CPU數量的1-2倍)。

還可以考慮使用任務並行庫(如Parallel.ForEach - http://msdn.microsoft.com/en-us/library/dd989744.aspx)來處理多個線程。

爲了儘量減少要處理的文件數量,我會保留已經處理的項目列表(即文件路徑+上次修改日期(除非您可以從其他來源獲取此信息))。

1

我的兩個主要問題是:

  1. 哪些文件的大小?
  2. 文件多久出現一次?

根據你的答案,我可能會用下面的生產者 - 消費者算法去:

  1. 使用文件系統觀察,看看有在該目錄正在監視
  2. 當活動活動發生,開始「輕鬆」輪詢;即測試每個文件是否可用,以查看它是否未鎖定(即,嘗試使用簡單的IsLocked擴展方法嘗試打開w/write權限,該方法通過try進行測試..抓住);如果一個或多個文件不空閒,請將計時器設置爲在某個時間段內關閉(如果希望文件更少或更短,則更短)以再次測試文件
  3. 只要您看到一個文件是免費的,處理它(即,將其移動到另一個文件夾,將一個項目放入一個併發隊列中,使用戶線程處理隊列,將文件/結果存檔)。
  4. 像Alexei提到的那樣(即磁盤/數據庫)有某種持久性機制能夠在系統故障的情況下恢復處理。

我覺得這是一個非阻塞,低cpu使用行爲的好組合。但測量你的前後結果。我會建議使用線程池,並儘量保持線程阻塞(即試圖通過不通過執行類似的Thread.Sleep阻止,以確保線程重新使用)

注:

  1. 基地的數量線程處理關於機器上可用的CPU和內核數量的文件;也考慮服務器負載
  2. FileSystemWatcher可以finicky;請確保它是從您正在監控的同一臺計算機上運行的(即不監視遠程服務器),否則您需要不時重新初始化連接。
  3. 我絕對不會爲每個文件產生不同的進程;多線程應該足夠大;重用線程是最好的。產卵過程是非常昂貴的操作,產卵線程是一項昂貴的操作。阿列克謝有一些好的信息與任務並行庫;它使用ThreadPool。
相關問題