C# C:从foreach循环每隔5分钟调用一个方法
我的控制台应用程序正在从文本文件中读取大量数据,这些数据将保存到数据库中。为此,我将数据存储到一个DataTable中,我想每5分钟将这个DataTable转储到一个DB中。如果我想一次转储整个数据,那么我必须用整个数据集填充DataTable,在这种情况下,我将退出MemoryExceptionC# C:从foreach循环每隔5分钟调用一个方法,c#,.net,multithreading,timer,C#,.net,Multithreading,Timer,我的控制台应用程序正在从文本文件中读取大量数据,这些数据将保存到数据库中。为此,我将数据存储到一个DataTable中,我想每5分钟将这个DataTable转储到一个DB中。如果我想一次转储整个数据,那么我必须用整个数据集填充DataTable,在这种情况下,我将退出MemoryException public void ProcessData() { string[] files=File.ReadAllLines(path) foreach(var item in files
public void ProcessData()
{
string[] files=File.ReadAllLines(path)
foreach(var item in files)
{
DataRow dtRow= dataTable.NewRow();
dtRow["ID"]= .... //some code here;
dtRow["Name"]= .... //some code here;
dtRow["Age"]= .... //some code here;
var timer = new Timer(v => SaveData(), null, 0, 5*60*1000);
}
}
public void SaveData(string tableName, DataTable dataTable )
{
//Some code Here
//After dumping data to DB, clear DataTable
dataTable.Rows.Clear();
}
这里我想要的是,代码将继续填充DataTable,并且每5分钟调用一次SaveData方法。此操作将继续运行,直到处理完所有文件
但是,我已经看到,当调用SaveData方法时,它会执行4-5次。有时,它每5分钟就会打一次电话
我不知道如何在这里继续。如何解决这个问题?这里可以使用其他方法吗?感谢您的帮助 必须使用ReadAllLines完全读取每个文本文件,这将消耗大量内存。为什么不从文件中读取x行,保存到数据库,然后继续,直到文件结束?是否必须使用ReadAllLines完全读取每个文本文件,这将消耗大量内存。为什么不从文件中读取x行,保存到数据库,然后继续,直到到达文件末尾?下面是关于如何实现代码的建议,以及另一个答案中的建议:
public void ProcessData()
{
int i = 1;
foreach(var item in File.ReadLines(path)) //This line has been edited
{
DataRow dtRow= dataTable.NewRow();
dtRow["ID"]= .... //some code here;
dtRow["Name"]= .... //some code here;
dtRow["Age"]= .... //some code here;
if (i%25 == 0) //you can change the 25 here to something else
{
SaveData(/* table name */, /* dataTable */);
}
i++;
}
SaveData(/* table name */, /* dataTable */);
}
public void SaveData(string tableName, DataTable dataTable )
{
//Some code Here
//After dumping data to DB, clear DataTable
dataTable.Rows.Clear();
}
以下是关于如何实施该准则的建议以及另一个答案的建议:
public void ProcessData()
{
int i = 1;
foreach(var item in File.ReadLines(path)) //This line has been edited
{
DataRow dtRow= dataTable.NewRow();
dtRow["ID"]= .... //some code here;
dtRow["Name"]= .... //some code here;
dtRow["Age"]= .... //some code here;
if (i%25 == 0) //you can change the 25 here to something else
{
SaveData(/* table name */, /* dataTable */);
}
i++;
}
SaveData(/* table name */, /* dataTable */);
}
public void SaveData(string tableName, DataTable dataTable )
{
//Some code Here
//After dumping data to DB, clear DataTable
dataTable.Rows.Clear();
}
最大的问题是在foreach中实例化新的计时器实例。每次foreach调用中的新计时器对象都意味着多个线程同时调用SaveData,这意味着dataTable被同时处理并保存到数据库中多次,很可能在清除行之前,从而将大部分文件复制到数据库中 在我提供问题的解决方案之前,我想指出,在5分钟的时间间隔内保存数据具有明显的代码味道。正如已经指出的那样,我建议使用某种方法,根据一定的数据大小而不是任意的时间间隔加载和保存数据。也就是说,我将继续回答您的问题,前提是您有理由必须以5分钟的间隔进行保存 首先,我们需要正确设置计时器,您会注意到我在foreach循环之外创建了计时器。继续按间隔运行,而不仅仅是等待和执行一次 其次,我们必须采取措施确保中间数据存储上的线程安全数据完整性在您使用DataTable的情况下,但我使用的是自定义类的列表,因为DataTable对于我们想要做的事情来说成本太高。你会注意到我在更新我们的列表之前完成了这项工作 数据处理类的更新:
private bool isComplete = false;
private object DataStoreLock = new object();
private List<MyCustomClass> myDataStore;
private Timer myTimer;
public void ProcessData()
{
myTimer = new Timer(SaveData, null, TimeSpan.Zero, TimeSpan.FromMinutes(5.0));
foreach (var item in File.ReadLines(path))
{
var myData = new MyCustomClass()
{
ID = 0, // Some code here
Name = "Some code here",
Age = 0 // Some code here
};
lock (DataStoreLock)
{
myDataStore.Add(myData);
}
}
isComplete = true;
}
public void SaveData(object arg)
{
// Our first step is to check if timed work is done.
if (isComplete)
{
myTimer.Dispose();
myTimer = null;
}
// Our next step is to create a local instance of the data store to work on, which
// allows ProcessData to continue populating while our DB actions are being performed.
List<MyCustomClass> lDataStore;
lock (DataStoreLock)
{
lDataStore = myDataStore;
myDataStore = new List<MyCustomClass>();
}
//Some code DB code here.
}
编辑:我已将枚举更改为通过ReadLines而不是ReadAllLines。阅读下面的评论。ReadAllLines将是一个阻塞调用,而ReadLines将允许在读取文件时处理枚举。我无法想象,如果文件已经全部读取到内存中,foreach将运行5分钟以上。最大的问题是在foreach中实例化新的计时器实例。每次foreach调用中的新计时器对象都意味着多个线程同时调用SaveData,这意味着dataTable被同时处理并保存到数据库中多次,很可能在清除行之前,从而将大部分文件复制到数据库中 在我提供问题的解决方案之前,我想指出,在5分钟的时间间隔内保存数据具有明显的代码味道。正如已经指出的那样,我建议使用某种方法,根据一定的数据大小而不是任意的时间间隔加载和保存数据。也就是说,我将继续回答您的问题,前提是您有理由必须以5分钟的间隔进行保存 首先,我们需要正确设置计时器,您会注意到我在foreach循环之外创建了计时器。继续按间隔运行,而不仅仅是等待和执行一次 其次,我们必须采取措施确保中间数据存储上的线程安全数据完整性在您使用DataTable的情况下,但我使用的是自定义类的列表,因为DataTable对于我们想要做的事情来说成本太高。你会注意到我在更新我们的列表之前完成了这项工作 数据处理类的更新:
private bool isComplete = false;
private object DataStoreLock = new object();
private List<MyCustomClass> myDataStore;
private Timer myTimer;
public void ProcessData()
{
myTimer = new Timer(SaveData, null, TimeSpan.Zero, TimeSpan.FromMinutes(5.0));
foreach (var item in File.ReadLines(path))
{
var myData = new MyCustomClass()
{
ID = 0, // Some code here
Name = "Some code here",
Age = 0 // Some code here
};
lock (DataStoreLock)
{
myDataStore.Add(myData);
}
}
isComplete = true;
}
public void SaveData(object arg)
{
// Our first step is to check if timed work is done.
if (isComplete)
{
myTimer.Dispose();
myTimer = null;
}
// Our next step is to create a local instance of the data store to work on, which
// allows ProcessData to continue populating while our DB actions are being performed.
List<MyCustomClass> lDataStore;
lock (DataStoreLock)
{
lDataStore = myDataStore;
myDataStore = new List<MyCustomClass>();
}
//Some code DB code here.
}
编辑:我已将枚举更改为通过ReadLines而不是ReadAllLines。阅读下面的评论。ReadAllLines将是一个阻塞调用,而ReadLines将允许在读取文件时处理枚举。我无法想象,如果文件已经全部读取到内存中,您的foreach将运行5分钟以上。pa如何
一旦你达到一个最大行数,你就可以遍历文本文件,然后将数据持久化到数据库中。如果在这几分钟内不知何故进行了更多的读取,你仍然可以将数据按时间转储到数据库中。您不应该在foreach中启动计时器,而是在每次达到任意行数时启动计时器-执行保存操作。在达到最大行数后,对文本文件进行分页,然后将数据持久化到数据库。按时间将数据转储到数据库,您仍然可以获得内存不足异常,如果在那几分钟里,有人读了更多的书。您不应该在foreach中启动计时器,而是应该在每次点击任意行数时启动计时器-执行save。是的,这也是可能的。感谢您的评论:。然而,我真的很感兴趣的是,这可以用定时器来完成吗?是的,这也是可能的。感谢您的评论:。然而,我真的很感兴趣的是,这可以用定时器完成吗?是的,这很好。但如果文件数为510,会发生什么?然后它将丢失最后10条记录。谢谢@Bunyip@Jsterman的提醒。我会小心File.Readlinespath.Count。ReadLines是为在枚举器前进时逐步遍历文件而构建的。您是否检查过该代码是否有效?即使是这样,看起来您还是要提前读取整个文件以获得该计数。@MikeGuthrie“file.ReadLinespath.count”可能读取整个文件,但它不会保存任何文件。这将需要一些时间,但根据,这是最节省内存的方法。我能想到的唯一其他方法是执行一个“while”语句,然后在代码周围放置一个“try”块,以捕获导致“File.ReadLinespath”到达文档末尾的错误,然后中断“while”循环。这可能会导致丢失一些错误。是的,这很好。但如果文件数为510,会发生什么?然后它将丢失最后10条记录。谢谢@Bunyip@Jsterman的提醒。我会小心File.Readlinespath.Count。ReadLines是为在枚举器前进时逐步遍历文件而构建的。您是否检查过该代码是否有效?即使是这样,看起来您还是要提前读取整个文件以获得该计数。@MikeGuthrie“file.ReadLinespath.count”可能读取整个文件,但它不会保存任何文件。这将需要一些时间,但根据,这是最节省内存的方法。我能想到的唯一其他方法是执行一个“while”语句,然后在代码周围放置一个“try”块,以捕获导致“File.ReadLinespath”到达文档末尾的错误,然后中断“while”循环。这可能会导致遗漏一些错误。