[英]C# Generic List foreach OutofMemoryException
我有一個程序,從數據庫中讀取大約200萬行到List。 每行是包含地理坐標等信息的位置。
將數據添加到List后,我使用foreach循環並獲取坐標以創建kml文件。 當行數很大時,循環遇到OutOfMemoryException錯誤(但是否則完美地工作)。
有關如何處理此問題的任何建議,以便程序可以處理非常大的數據集? kml庫是SharpKML。
我還是C#的新手,所以請放輕松!
這是循環:
using (SqlConnection conn = new SqlConnection(connstring))
{
conn.Open();
SqlCommand cmd = new SqlCommand(select, conn);
using (cmd)
{
SqlDataReader reader = cmd.ExecuteReader();
while (reader.Read())
{
double lat = reader.GetDouble(1);
double lon = reader.GetDouble(2);
string country = reader.GetString(3);
string county = reader.GetString(4);
double TIV = reader.GetDouble(5);
double cnpshare = reader.GetDouble(6);
double locshare = reader.GetDouble(7);
//Add results to list
results.Add(new data(lat, lon, country, county, TIV, cnpshare, locshare));
}
reader.Close();
}
conn.Close();
}
int count = results.Count();
Console.WriteLine("number of rows in results = " + count.ToString());
//This code segment generates the kml point plot
Document doc = new Document();
try
{
foreach (data l in results)
{
Point point = new Point();
point.Coordinate = new Vector(l.lat, l.lon);
Placemark placemark = new Placemark();
placemark.Geometry = point;
placemark.Name = Convert.ToString(l.tiv);
doc.AddFeature(placemark);
}
}
catch(OutOfMemoryException e)
{
throw e;
}
這是列表中使用的類
public class data
{
public double lat { get; set; }
public double lon { get; set; }
public string country { get; set; }
public string county { get; set; }
public double tiv { get; set; }
public double cnpshare { get; set; }
public double locshare { get; set; }
public data(double lat, double lon, string country, string county, double tiv, double cnpshare,
double locshare)
{
this.lat = lat;
this.lon = lon;
this.country = country;
this.county = county;
this.tiv = tiv;
this.cnpshare = cnpshare;
this.locshare = locshare;
}
}
為什么在編寫之前需要存儲所有數據? 不是將每一行添加到列表中,而是應該在讀取時處理每一行,然后忘記它。
例如,嘗試將代碼一起滾動如下:
Document doc = new Document();
while (reader.Read())
{
// read from db
double lat = reader.GetDouble(1);
double lon = reader.GetDouble(2);
string country = reader.GetString(3);
string county = reader.GetString(4);
double TIV = reader.GetDouble(5);
double cnpshare = reader.GetDouble(6);
double locshare = reader.GetDouble(7);
var currentData = new data(lat, lon, country, county, TIV, cnpshare, locshare));
// write to file
Point point = new Point();
point.Coordinate = new Vector(currentData.lat, currentData.lon);
Placemark placemark = new Placemark();
placemark.Geometry = point;
placemark.Name = Convert.ToString(currentData.tiv);
doc.AddFeature(placemark);
}
這只有在Document
合理實施的情況下才有效。
奧利弗是對的(從我這里投票)。 性能方面你可以做一些其他的事情。 首先不要查詢您不會使用的字段。 然后在while語句(?)之前移動所有變量聲明(Oliver的代碼)。 最后,不是等待你的sql server收集並發回所有記錄,而是逐步執行步驟。 例如,如果您的記錄具有UID,並且獲取它們的順序是此UID,則從本地C#變量“var lastID = 0”開始,將您的select語句更改為類似(預格式化)“select top 1000 ...其中UID> lastID“並重復您的查詢,直到您什么都沒有或任何東西少於1000條記錄。
如果使用數據庫中的數據填充列表沒有大的延遲,並且您沒有提到使用數據填充列表時出現問題,為什么不立即創建Point和Placemark對象。 代碼如下。
var doc = new Document();
using (SqlConnection conn = new SqlConnection(connstring))
{
conn.Open();
SqlCommand cmd = new SqlCommand(select, conn);
using (cmd)
{
var reader = cmd.ExecuteReader();
while (reader.Read())
{
double lat = reader.GetDouble(1);
double lon = reader.GetDouble(2);
string country = reader.GetString(3);
string county = reader.GetString(4);
double TIV = reader.GetDouble(5);
double cnpshare = reader.GetDouble(6);
double locshare = reader.GetDouble(7);
var point = new Point();
point.Coordinate = new Vector(lat , lon );
var placemark = new Placemark();
placemark.Geometry = point;
placemark.Name = Convert.ToString(TIV);
doc.AddFeature(placemark);
reader.Close();
}
conn.Close();
}
如果沒有充分的理由在內存中檢索如此多的數據,請嘗試使用一些延遲加載方法。
@drdigit,
我會避免在循環中執行查詢。 一個查詢應始終返回該時刻所需的數據。 在這種情況下,您將有1000個返回1000行的查詢。 也許最好快速顯示前1000行,但我不確定如果你在循環中執行1000個更快的查詢而不是只執行一個查詢它會更快。也許我錯了....
我認為如果在這種情況下需要,你的方法對延遲加載很有用。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.