使用线程时出现内存不足异常

5

I have the following algorithm ,

private void writetodb()
{
    using(var reader = File.OpenRead("C:\Data.csv");
    using(var parser = new TextFieldParser(reader))
    { 
        //Do some opeartions
        while(!parser.EndOfData)
        {
            //Do operations
            //Take 500 rows of data and put it in dataset
            Thread thread = new thread(() => WriteTodb(tablename, set));
            thread.Start();
            Thread.Sleep(5000);
        }
    }
}

public void WriteTodb(string table, CellSet set)
{
    //WriteToDB
    //Edit: This statement will write to hbase db in hdinsight
    hbase.StoreCells(TableName, set);
}

这种方法对于不超过500 mb的数据完全正常,但在此之后会出现内存溢出异常

我非常确定这是由于线程造成的,但使用线程是必须的,我无法改变架构。
有人能告诉我在上述程序中需要进行哪些线程编程修改以避免内存异常吗?


6
一个线程占用大约1MB的内存。鉴于数据量(500MB!),你的程序可能会耗尽内存。考虑使用任务并行库而不是手动创建线程。 - Cristian Lupascu
同时,检查数据集的写操作是否具有线程安全性。 - Cristian Lupascu
4
你确定必须使用线程吗?不能使用任务吗?此外,你确定线程不会争夺你正在使用的资源(我猜是文件)吗? - Theodoros Chatzigiannakis
4
使用线程进行I/O操作非常低效,你应该使用async/await。 - Dour High Arch
实际上从文件中读取数据的代码在哪里?目前的代码看起来像是一个无限循环,因为 parser.EndOfData 总是返回 false... - tzachs
显示剩余2条评论
2个回答

6
首先,我无法理解您关于线程的话语:

我必须在上述程序中进行线程编程,以避免内存异常。

如果您使用TPL,则将使用线程编程,正如已经建议的那样。 如果您无法理解,则确实不必使用Thread类。 您说您的代码是C#4.0,因此TPL对您来说是一种选择。 您可以像这样轻松地完成工作:
List<Task> tasks  = new List<Task>();
while(!parser.EndOfData)
{
    tasks.Add(Task.Run(() => WriteTodb(tablename, set)));
}
Task.WaitAll(tasks.ToArray());

TPL引擎将使用默认的TaskScheduler类,该类使用内部的ThreadPool,可以平衡服务器上的资源。

此外,我看到您正在使用Microsoft的HBase客户端,并且它在其中有async方法

public async Task StoreCellsAsync(string table, CellSet cells)
{
}

因此,您可以在代码中同时使用异步方法和TPL

List<Task> tasks  = new List<Task>();
while(!parser.EndOfData)
{
    tasks.Add(WriteTodb(tablename, set)));
}
// asynchroniously await all the writes
await Task.WhenAll(tasks.ToArray());

public async Task WriteTodb(string table,CellSet set)
{
    //WriteToDB
    //Edit: This statement will write to hbase db in hdinsight asynchroniously!
    await hbase.StoreCellsAsync(TableName, set);
}

如果由于某种奇怪的原因,您无法使用TPL,则必须重构代码并编写自己的线程调度程序:
  1. 您不必每次为写入创建线程,可以重复使用它们。
  2. 通常情况下,在同一线程中第二次运行比为每个操作创建两个不同的线程更快。
  3. 将文件分成几个部分,为写入创建线程,并在循环中写入数据。

0

2
这是一般情况下的好建议,但它并没有真正回答问题。 - Brian Rasmussen

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接