“同时”阅读大量文件

时间:2015-12-03 09:59:46

标签: c# io

我正在使用FileSystemWatcher来抓住文件夹中任何文件的每个createdchangeddeletedrenamed更改。

通过这些更改,我需要对这些文件的内容执行简单的校验和。简单地说,我正在打开一个文件流并将其传递给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个calculateChecksum()执行。

我怎么能解决这类问题?

2 个答案:

答案 0 :(得分:2)

from kivy.app import App from kivy.uix.boxlayout import BoxLayout from kivy.uix.dropdown import DropDown from kivy.uix.button import Button from kivy.uix.screenmanager import ScreenManager, Screen from kivy.uix.textinput import TextInput from kivy.properties import ListProperty, StringProperty import re from kivy.lang import Builder Builder.load_string(''' <Intro>: BoxLayout: Button: text: 'Press to go to SecondScreen' font_size: '20px' on_release: root.manager.current = 'SecondScreen' <SecondScreen>: ComboLayout: Label: text: "working?" font_size: '20px' ComboEdit: size_hint: .5, .5 pos_hint: {'center':(.5, .5)} font_size: '100px' multiline: False ''') class ComboEdit(TextInput): options = ListProperty([]) def __init__(self, **kw): super(ComboEdit, self).__init__(**kw) self.ddn = DropDown() self.ddn.bind(on_select=self.on_select) def on_options(self, instance, value): for option in value: but = Button(text=option, size_hint_y=None, height='36sp', on_release=lambda btn: self.ddn.select(btn.text)) self.ddn.add_widget(but) def on_select(self, instance, value): self.text = value def on_text(self, instance, value): self.options = [str(i) for i in range(0,8)] if not self.get_root_window(): return # do proceed if I'm not displayed <=> If have no parent self.ddn.open(self) class ComboLayout(BoxLayout): pass class Intro(Screen): pass class SecondScreen(Screen): pass class BugDemoApp(App): def build(self): sm = ScreenManager() sm.add_widget(Intro(name='Intro')) sm.add_widget(SecondScreen(name='SecondScreen')) return sm if __name__ == '__main__': BugDemoApp().run() 处理程序中,将任务放入将由某个worker处理的队列。工作人员可以以目标速度或/和频率处理校验和计算任务。可能一个工人会更好,因为许多读者可以通过许多阅读寻求减慢硬盘。

尝试阅读有关BlockingCollection的信息: https://msdn.microsoft.com/ru-ru/library/dd997371(v=vs.110).aspx

和生产者 - 消费者数据流模式 https://msdn.microsoft.com/ru-ru/library/hh228601(v=vs.110).aspx

FileSystemWatcher

//在FileSystemWatcher处理程序内部

var workerCount = 2;
BlockingCollection<String>[] filesQueues= new BlockingCollection<String>[workerCount];

for(int i = 0; i < workerCount; i++)
{
    filesQueues[i] = new BlockingCollection<String>(500);

    // Worker
    Task.Run(() => 
    {
        while (!filesQueues[i].IsCompleted)
        {
            string url;

            try
            {
                url= filesQueues[i].Take();
            }
            catch (InvalidOperationException) { }

            if (!string.IsNullOrWhiteSpace(url))
            {
                calculateChecksum(url);
            }
        }
    }
}

此外,您可以创建多个消费者,只需同时调用Take或TryTake - 每个项目仅由单个消费者使用。但考虑到在这种情况下,许多工作人员可以处理一个文件,而多个硬盘读取器可以减慢硬盘驱动器。

在多个工作人员的情况下UPD,最好进行多个BlockingCollections,并使用索引推送队列中的文件:

答案 1 :(得分:0)

我已经设置了一个 cosumer-producer 模式来解决这个问题,我尝试使用一个线程池来平滑大量的工作,共享一个{ {1}}

BlockingCollection&amp;线程池

BlockingCollection

正如你所看到的,我已经创建了一个I treadPool设置并发为4.因此,无论是否有private BlockingCollection<Index.ResourceIndexDocument> documents; this.pool = new SmartThreadPool(SmartThreadPool.DefaultIdleTimeout, 4); this.documents = new BlockingCollection<string>(); 工作,都会同时只有4个线程工作。在游泳池中处理的单位。

<强>生产者

x > 4

<强>消费

public void warn(string channel, string frl)
{
    this.pool.QueueWorkItem<string, string>(
        (file) => this.files.Add(file),
        channel,
        frl
    );
}