C# “阅读大量文件”;同时";
我正在使用C# “阅读大量文件”;同时";,c#,io,C#,Io,我正在使用FileSystemWatcher来捕获文件夹中任何文件中创建的、更改的、删除的和重命名的更改 在这些更改中,我需要对这些文件的内容执行简单的校验和。简单地说,我正在打开一个文件流并将其传递给MD5类: private byte[] calculateChecksum(string frl) { using (FileStream stream = File.Open(frl, FileMode.Open, FileAccess.Read, FileShare.ReadWrit
FileSystemWatcher
来捕获文件夹中任何文件中创建的、更改的、删除的和重命名的更改
在这些更改中,我需要对这些文件的内容执行简单的校验和。简单地说,我正在打开一个文件流并将其传递给MD5类:
private byte[] calculateChecksum(string frl)
{
using (FileStream stream = File.Open(frl, FileMode.Open, FileAccess.Read, FileShare.ReadWrite))
{
return this.md5.ComputeHash(stream);
}
}
问题在于我需要处理的文件数量。例如,假设我在一个文件夹中创建了200个文件,然后复制所有文件并粘贴到同一文件夹中。此操作将导致200个事件和200个执行
如何解决此类问题?在FileSystemWatcher
handler中,处理程序将任务放入将由某个工作者处理的队列。工作人员可以以目标速度或/和频率处理校验和计算任务。可能一个工人会更好,因为许多读卡器可以通过许多读搜索减慢硬盘速度
尝试阅读有关BlockingCollection的内容:
生产者和消费者数据流模式
此外,您还可以创建多个消费者,只需同时调用Take或TryTake即可-每个商品将仅由一个消费者消费。但考虑到在这种情况下,一个文件可以由许多工作人员处理,而多个hdd读卡器可能会降低hdd的速度
UPD如果有多个worker,最好创建多个BlockingCollection,并使用索引将文件推送到队列中:我已经设置了一个cosumer-producer模式来解决这个问题,我尝试使用线程池来平滑大量工作,共享一个BlockingCollection
阻止收集和线程池:
private BlockingCollection<Index.ResourceIndexDocument> documents;
this.pool = new SmartThreadPool(SmartThreadPool.DefaultIdleTimeout, 4);
this.documents = new BlockingCollection<string>();
public void warn(string channel, string frl)
{
this.pool.QueueWorkItem<string, string>(
(file) => this.files.Add(file),
channel,
frl
);
}
Task.Factory.StartNew(() =>
{
Index.ResourceIndexDocument document = null;
while (this.documents.TryTake(out document, TimeSpan.FromSeconds(1)))
{
IEnumerable<Index.ResourceIndexDocument> documents = this.documents.Take(this.documents.Count);
Index.IndexEngine.Instance.index(documents);
}
},
TaskCreationOptions.LongRunning
);
消费者:
private BlockingCollection<Index.ResourceIndexDocument> documents;
this.pool = new SmartThreadPool(SmartThreadPool.DefaultIdleTimeout, 4);
this.documents = new BlockingCollection<string>();
public void warn(string channel, string frl)
{
this.pool.QueueWorkItem<string, string>(
(file) => this.files.Add(file),
channel,
frl
);
}
Task.Factory.StartNew(() =>
{
Index.ResourceIndexDocument document = null;
while (this.documents.TryTake(out document, TimeSpan.FromSeconds(1)))
{
IEnumerable<Index.ResourceIndexDocument> documents = this.documents.Take(this.documents.Count);
Index.IndexEngine.Instance.index(documents);
}
},
TaskCreationOptions.LongRunning
);
Task.Factory.StartNew(()=>
{
Index.ResourceIndexDocument文档=null;
while(this.documents.TryTake(out document,TimeSpan.FromSeconds(1)))
{
IEnumerable documents=this.documents.Take(this.documents.Count);
Index.IndexEngine.Instance.Index(文档);
}
},
TaskCreationOptions.LongRunning
);
您考虑过工作池吗?如中所示:将作业添加到某个执行引擎中,并在作业进入时(根据可用线程的数量)对其进行处理。我认为某种c#async wait magic能够以非常简单的方式实现这一点。如果打开这么多文件会导致性能问题,您可以实现队列并限制工作线程的数量。您已经有了一个工作池。检查,是的。它需要一个混合:生产者-消费者线程模式和消费者池。有生产者
(FileSystemWatcher的事件)产生要处理的项,有几个消费者
处理它们。下一步是,如何合并或联接操作。因此,我需要一个consumer
同时处理x
项。@Jordi,您可以创建多个consumer,但要小心,它可能会使硬盘性能下降,因为我不了解上一个UPD。“使用索引“?@Jordi在QUU中推送文件”为防止多个工作人员同时处理一个文件时出现这种情况,必须始终使用同一个工作人员处理一个文件,如果您为每个使用者进行BlockingCollection并使用某些规则为每个文件选择队列,则可以确定。现在,我明白了,我需要为我的BlockingCollection
提供信息。现在的问题是,我不太明白如何开发一个消费者
,它在这个集合中永久地出现,并根据实际元素从BlocingCollection
中提取x
并处理它们……我现在面临的问题是我需要使用一组文件GetConsumingEnumerable()
枚举BlockingCollection
上的每个string
,但是我需要同时处理所有元素。属性“Count”和方法TryTake几乎没有超时()尝试使用属性“Count”获取集合中的所有元素并将其放入数组或smth。此外,BlockingCollection包含方法TryTake,若您在循环中使用该方法时几乎并没有超时,那个么您可以读取所有已存在的方法。在你得到超时时间后,请接受usal。我已经改变了我的消费者。我不知道这是否如你所评论的那样。现在的问题是,采用方法。它不会从反收集中删除元素!