[英]How to process files in directory concurrently in .net
我在目錄內並行處理文件時遇到問題。 我已經閱讀了幾個類似的問題和示例,但是我似乎找不到為什么我的代碼導致異常的原因。
我的目錄由其他進程填充,並且隨時包含數千個文件。 每個文件都必須進行解析和驗證,這需要花費時間文件系統/網絡io等。我需要並行執行此步驟,其余步驟必須串行執行。
這是我的代碼:
public void run()
{
XmlMessageFactory factory = new XmlMessageFactory();
DirectoryInfo dir = new DirectoryInfo(m_sourceDir);
Dictionary<string, int> retryList = new Dictionary<string, int>();
ConcurrentQueue<Tuple<XmlMsg,FileInfo>> MsgQueue = new
ConcurrentQueue<Tuple<XmlMsg,FileInfo>>();
//start worker to handle messages
System.Threading.ThreadPool.QueueUserWorkItem(o =>
{
XmlMsg msg;
Tuple<XmlMsg, FileInfo> item;
while (true)
{
if (!MsgQueue.TryDequeue(out item))
{
System.Threading.Thread.Sleep(5000);
continue;
}
try
{
msg = item.Item1;
/* processing on msg happens here */
handleMessageProcessed(item.Item2, ref retryList);
}
catch (Exception e)
{
//if this method is called it gives the
//exception below
handleMessageFailed(item.Item2, e.ToString());
}
}
}
);
while (true)
{
try
{
FileInfo[] files = dir.GetFiles(m_fileTypes);
Partitioner<FileInfo> partitioner = Partitioner.Create(files, true);
Parallel.ForEach(partitioner, f =>
{
try
{
XmlMsg msg = factory.getMessage(messageType);
try
{
msg.loadFile(f.FullName);
MsgQueue.Enqueue(new Tuple<XmlMsg, FileInfo>(msg, f));
}
catch (Exception e)
{
handleMessageFailed(f, e.ToString());
}
}
});
}
}
}
static void handleMessageFailed(FileInfo f, string message)
{
//Erorr here:
f.MoveTo(m_failedDir + f.Name);
//"The process cannot access the file because it is
//being used by another process."} System.Exception {System.IO.IOException}
}
使用ConcurrentQueue如何最終導致嘗試同時訪問兩次文件?
我目前有一個包含5000個文件的測試設置,並且每次運行至少會發生一次,並且每次都會在一個不同的文件上發生。 當我檢查目錄時,導致異常的源文件將已經被處理,並且位於“已處理”目錄中。
經過一番撓頭之后,問題變得很簡單! 發生的事情是在文件上的串行活動之前完成了目錄中文件的並行處理,因此循環正在重新啟動,並將其中已經存在的某些文件重新添加到隊列中。
為了完整起見,這是修改后的代碼部分:
while (true)
{
try
{
FileInfo[] files = dir.GetFiles(m_fileTypes);
Partitioner<FileInfo> partitioner = Partitioner.Create(files, true);
Parallel.ForEach(partitioner, f =>
{
try
{
XmlMsg msg = factory.getMessage(messageType);
try
{
msg.loadFile(f.FullName);
MsgQueue.Enqueue(new Tuple<XmlMsg, FileInfo>(msg, f));
}
catch (Exception e)
{
handleMessageFailed(f, e.ToString());
}
}
});
//Added check to wait for queue to deplete before
//re-scanning the directory
while (MsgQueue.Count > 0)
{
System.Threading.Thread.Sleep(5000);
}
}
}
我懷疑XmlMsg.loadFile()
有問題
我認為您可能在其中包含以下代碼:
public void loadFile(string filename)
{
FileStream file = File.OpenRead(filename);
// Do something with file
file.Close();
}
如果“用文件執行操作”部分發生異常,則不會關閉文件,因為file.Close()
將永遠不會執行。 然后,您將在handleMessageFailed()
獲得“正在使用文件”異常。
如果是這樣,解決方案是按以下方式在using
塊中訪問文件; 那么它將在發生異常時關閉:
public void loadFile(string filename)
{
using (FileStream file = File.OpenRead(filename))
{
// Do something with file
}
}
但是假設這確實是問題所在,當您開始使用外部進程生成的實際文件時,如果外部線程在工作線程嘗試處理它們時仍打開文件,則可能會遇到另一個問題。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.