【发布时间】:2015-05-27 23:03:11
【问题描述】:
我正在创建一个 Windows 窗体应用程序,我在其中选择了一个包含多个 *.txt 文件的文件夹。它们的长度可能从几千行 (kB) 到多达 5000 万行 (1GB) 不等。代码的每一行都包含三个信息。 long 中的日期,int 中的位置 id 和 float 中的值都用分号 (;) 分隔。我需要计算所有这些文件中的最小值和最大值,并告诉它在哪个文件中,然后是最常见的值。
我已经验证了这些文件并将其存储在数组列表中。我正在打开一个线程来逐个读取文件,然后逐行读取数据。它工作正常,但是当有 1GB 文件时,我的内存不足。我试图将值存储在字典中,其中键是日期,值是一个对象,其中包含从该行加载的所有信息以及文件名。我看到我不能使用字典,因为在大约 6M 值时,我的内存不足。所以我可能应该用多线程来做。我虽然可以运行两个线程,一个读取文件并将信息放入某种容器中,另一个从中读取并进行计算,然后从容器中删除值。但我不知道哪个容器可以做这样的事情。此外,我需要计算最常见的值,因此需要将它们存储在某个地方,这会导致我回到某种字典,但我已经知道我会用完内存。我也没有太多线程经验,所以我不知道有什么可能。到目前为止,这是我的代码:
图形界面:
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");
}
}
}
}
}
}
以及我从行中放入值的对象: 入口.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;
}
}
}
【问题讨论】:
-
TL;博士; MCVE
-
多线程在这里肯定帮不了你,因为引入更多线程并不会神奇地为你的进程增加更多内存。编辑问题,以便删除对多线程的任何提及。同时删除 GUI 代码,因为这不是问题。
-
内存不足是一个相当愚蠢的问题,现代计算机有很多。 1 TB 非常容易获得,而且也不花钱。 Project + Properties,Build选项卡,将Platform target设置更改为AnyCPU,看到“Prefer 32-bit”选项时取消勾选。你不喜欢它。
-
我已经清理了代码。那么不应该有任何类型的多线程吗?就像我说的,如果我可以在一个线程中从容器中读取并同时写入新值,它会“给我更多内存”,因为我不必再存储这些东西了,对吧?但是频率有问题。
-
@HansPassant 你是什么意思?所有对象在 32b 和 64b 中都有 2GB 大小的限制。我指的是(stackoverflow.com/questions/3657181/…)。此外,我应该运行这个应用程序的计算机根本不是现代的。它有 Intel Core 2 Duo L7500 和 3GB Ram
标签: c# multithreading winforms thread-safety