繁体   English   中英

在C#中使用多线程处理多个文件的最佳方法是什么?

[英]What is the best way to work with multiple files in multithread in C#?

我正在创建Windows窗体应用程序,在其中选择包含多个* .txt文件的文件夹。 它们的长度可能从几千行(kB)到多达5,000万行(1GB)不等。 该代码的每一行都有三个信息。 日期以long表示,位置id以int表示,值float以分号(;)分隔。 我需要计算所有这些文件中的最小值和最大值,并告诉它在哪个文件中,然后是最频繁的值。

我已经将这些文件验证并存储在arraylist中。 我正在打开一个线程来逐个读取文件,然后逐行读取数据。 它工作正常,但是当有1GB文件时,我的内存不足。 我试图将值存储在字典中,其中key将是日期,而值将是一个对象,其中包含从该行加载的所有信息以及文件名。 我看到我无法使用字典,因为在大约6M的值时,我内存不足。 所以我可能应该在多线程中执行。 虽然我可以运行两个线程,一个线程读取文件并将信息放入某种容器中,另一个线程从文件读取并进行计算,然后从容器中删除值。 但是我不知道哪个容器可以做到这一点。 此外,我需要计算最频繁的值,因此它们需要存储在某个位置,这会使我回到某种字典中,但是我已经知道我将用光内存。 我也没有太多的线程经验,所以我不知道有什么可能。 到目前为止,这是我的代码:

GUI:

namespace STI {
    public partial class GUI : Form {
        private String path = null;
        public static ArrayList txtFiles;

        public GUI() {
            InitializeComponent();
            _GUI1 = this;
        }

       //I run it in thread. I thought I would run the second 
       //one here that would work with the values inputed in some container
        private void buttonRun_Click(object sender, EventArgs e) {
            ThreadDataProcessing processing = new ThreadDataProcessing();
            Thread t_process = new Thread(processing.runProcessing);
            t_process.Start();

            //ThreadDataCalculating calculating = new ThreadDataCalculating();
            //Thread t_calc = new Thread(calculating.runCalculation());
            //t_calc.Start();

        }


    }
}

ThreadProcessing.cs

namespace STI.thread_package {
    class ThreadDataProcessing {
        public static Dictionary<long, object> finalMap = new Dictionary<long, object>();

        public void runProcessing() {
            foreach (FileInfo file in GUI.txtFiles) {
                using (FileStream fs = File.Open(file.FullName.ToString(), FileMode.Open))
                using (BufferedStream bs = new BufferedStream(fs))
                using (StreamReader sr = new StreamReader(bs)) {
                    String line;
                    String[] splitted;
                    try { 
                        while ((line = sr.ReadLine()) != null) {
                            splitted = line.Split(';');

                            if (splitted.Length == 3) {
                                long date = long.Parse(splitted[0]);
                                int location = int.Parse(splitted[1]);
                                float value = float.Parse(splitted[2], CultureInfo.InvariantCulture);

                                Entry entry = new Entry(date, location, value, file.Name);

                                if (!finalMap.ContainsKey(entry.getDate())) {
                                    finalMap.Add(entry.getDate(), entry);

                                }
                            }
                        }
                        GUI._GUI1.update("File \"" + file.Name + "\" completed\n");
                    }
                    catch (FormatException ex) {
                        GUI._GUI1.update("Wrong file format.");
                    }
                    catch (OutOfMemoryException) {
                        GUI._GUI1.update("Out of memory");
                    }
                }

            }
        }
    }
}

以及将行中的值放入其中的对象:Entry.cs

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace STI.entities_package {
    class Entry {
        private long date;
        private int location;
        private float value;
        private String fileName;
        private int count;

        public Entry(long date, int location, float value, String fileName) {
            this.date = date;
            this.location = location;
            this.value = value;
            this.fileName = fileName;

            this.count = 1;
        }

        public long getDate() {
            return date;
        }

        public int getLocation() {
            return location;
        }

        public String getFileName() {
            return fileName;
        }

    }
}

我认为多线程不会在这里为您提供帮助-它可以帮助您将IO绑定任务与CPU绑定任务分开,但是您的CPU绑定任务是如此琐碎,以至于我认为它们并不能保证自己的任务线。 多线程将要做的所有事情不必要地增加了问题的复杂性。

计算常量内存中的最小值/最大值很简单:只需维护一个minFile和maxFile变量,当当前文件的值小于minFile或大于maxFile时,该变量将更新。 找到最频繁的值将需要更多的内存,但是只有几百万个文件,您应该有足够的RAM来存储Dictionary<float, int>来维护每个值的频率,此后您遍历映射到确定哪个值具有最高频率。 如果由于某种原因您没有足够的RAM(如果内存不足,请确保关闭文件并进行垃圾回收,因为带有几百万个条目的Dictionary<float, int>应该小于那么您可以对文件进行多次传递:在第一次传递时,将值存储在Dictionary<interval, int> ,其中您将MIN_FLOAT和MAX_FLOAT之间的间隔分成了几千个子间隔,那么在下一遍,您可以忽略所有不符合最高频率间隔的值,从而缩小字典的大小。 但是, Dictionary<float, int>应该适合内存,因此,除非您开始处理数十亿个文件而不是数百万个文件,否则可能不需要多遍处理。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM