我有一些示例应用程序我正在努力尝试获得一些新的.Net 4.0 Parallel Extensions(它们非常好)。我遇到了OutOfMemoryException的(可能真的很愚蠢)问题。我的主要应用程序,我正在寻找插入此示例读取一些数据和大量文件,对它们进行一些处理,然后将它们写出来。我遇到了一些问题,文件变得越来越大(可能是GB)并且担心内存,所以我想并行化导致我走这条道路的事情。
现在,下面的代码在较小的文件上获取OOME,我想我只是遗漏了一些东西。它将读入10-15个文件并很好地将它们写在parellel中,但随后它会在下一个文件中窒息。看起来它的读写速度约为650MB。第二组眼睛将不胜感激。
我正在从FileStream读取MemorySteam,因为这是主应用程序所需要的,我只是想在某种程度上复制它。它从所有类型的地方读取数据和文件,并作为MemoryStreams处理它们。
这是使用.Net 4.0 Beta 2,VS 2010。
namespace ParellelJob
{
class Program
{
BlockingCollection<FileHolder> serviceToSolutionShare;
static void Main(string[] args)
{
Program p = new Program();
p.serviceToSolutionShare = new BlockingCollection<FileHolder>();
ServiceStage svc = new ServiceStage(ref p.serviceToSolutionShare);
SolutionStage sol = new SolutionStage(ref p.serviceToSolutionShare);
var svcTask = Task.Factory.StartNew(() => svc.Execute());
var solTask = Task.Factory.StartNew(() => sol.Execute());
while (!solTask.IsCompleted)
{
}
}
}
class ServiceStage
{
BlockingCollection<FileHolder> outputCollection;
public ServiceStage(ref BlockingCollection<FileHolder> output)
{
outputCollection = output;
}
public void Execute()
{
var di = new DirectoryInfo(@"C:\temp\testfiles");
var files = di.GetFiles();
foreach (FileInfo fi in files)
{
using (var fs = new FileStream(fi.FullName, FileMode.Open, FileAccess.Read))
{
int b;
var ms = new MemoryStream();
while ((b = fs.ReadByte()) != -1)
{
ms.WriteByte((byte)b); //OutOfMemoryException Occurs Here
}
var f = new FileHolder();
f.filename = fi.Name;
f.contents = ms;
outputCollection.TryAdd(f);
}
}
outputCollection.CompleteAdding();
}
}
class SolutionStage
{
BlockingCollection<FileHolder> inputCollection;
public SolutionStage(ref BlockingCollection<FileHolder> input)
{
inputCollection = input;
}
public void Execute()
{
FileHolder current;
while (!inputCollection.IsCompleted)
{
if (inputCollection.TryTake(out current))
{
using (var fs = new FileStream(String.Format(@"c:\temp\parellel\{0}", current.filename), FileMode.OpenOrCreate, FileAccess.Write))
{
using (MemoryStream ms = (MemoryStream)current.contents)
{
ms.WriteTo(fs);
current.contents.Close();
}
}
}
}
}
}
class FileHolder
{
public string filename { get; set; }
public Stream contents { get; set; }
}
}
答案 0 :(得分:4)
主逻辑似乎没问题,但是如果在main中的那个空的while循环是文字,那么你正在烧掉不必要的CPU周期。最好更好地使用solTask.Wait()。
但是如果单个文件可以以GB为单位运行,那么你仍然存在至少在内存中保存1个的问题,通常是2个(1个正在读取,1个正在处理/写入。
PS1:我刚刚意识到你没有预先分配MemStream。这很糟糕,它必须经常为一个大文件重新调整大小,这会花费大量内存。更好地使用类似的东西:
var ms = new MemoryStream(fs.Length);
然后,对于大文件,您必须考虑大对象堆(LOH)。您确定无法分段处理文件并处理它们吗?
PS2:你不需要构造函数参数的参考,但这不是问题。
答案 1 :(得分:0)
快速查看,在您的ServiceStage.Execute方法中
var ms = new MemoryStream();
我没有看到你在哪里关闭ms或者在使用中。你确实在其他课程中使用。这是一回事。