如何使用 Encoding.ASCII.GetBytes 处理大量数据? (抛出 OutOfMemoryException)
How to use Encoding.ASCII.GetBytes with large amounts of data? (throws OutOfMemoryException)
我在将字符串转换为字节数组时出现内存不足异常。
if (message.Contains("REQZ1S"))
{
string strMsg = "REQZID;";
try
{
var tmp = LoadCellService.readFromExcel(LoadCellModel.LoadCellRowList.Where(x => x.Stage == 1).ToList(), 1);
LogHelper.StartTo(nameof(LoadCellSiemensOPCModel), $"tmp count: {tmp.Item1.Count}");
if (tmp.Item1 != null)
{
tmp.Item1.ForEach(
z => LoadCellModel.LoadCellRowList.Where(x => x.Stage == z.Stage && x.RowIndex == z.RowIndex).First().LoadCellRowColumnList = z.LoadCellRowColumnList
);
LoadCellModel.LoadCellRowList.ForEach(
x => x.LoadCellRowColumnList.ForEach(y =>
{
LogHelper.StartTo("temp", y.LoadCellRowColumnKey + ";" + y.LoadCellRowColumnValue);
if (y.LoadCellRowColumnKey == "Distance")
{
strMsg += strMsg + ";" + y.LoadCellRowColumnValue;
}
})
);
LogHelper.KeyValue(nameof(LoadCellSiemensOPCModel), "message2", strMsg);
byte[] msg = System.Text.Encoding.ASCII.GetBytes(strMsg + "\r");
Stream.Write(msg, 0, msg.Length);
LogHelper.KeyValue(nameof(LoadCellSiemensOPCModel), "message", strMsg);
LogHelper.SiemensOPCTrace(nameof(LoadCellSiemensOPCModel), $"Write <<< {strMsg}");
}
else
{
byte[] msg = System.Text.Encoding.ASCII.GetBytes("REQZ1E;\r");
Stream.Write(msg, 0, msg.Length);
LogHelper.SiemensOPCTrace(nameof(LoadCellSiemensOPCModel), $"Write <<< REQZ1E;");
}
LogHelper.Done(nameof(LoadCellSiemensOPCModel), $"Write <<< REQZ1S;");
}
catch (Exception EX)
{
LogHelper.KeyValue(nameof(LoadCellSiemensOPCModel), "message1", strMsg);
LogHelper.Error("TEMP", EX);
}
}
我怀疑这部分还需要添加一些适当的逻辑:
byte[] msg = System.Text.Encoding.ASCII.GetBytes(strMsg + "\r");
Stream.Write(msg, 0, msg.Length);
问题不是 System.Text.Encoding.ASCII.GetBytes("REQZ1E;\r");
- 问题在这里:
LoadCellModel.LoadCellRowList.ForEach(
x => x.LoadCellRowColumnList.ForEach(y => {
// ...
strMsg += strMsg + ";" + y.LoadCellRowColumnValue;
// ...
}
使用 +=
运算符连接字符串 会导致整个字符串的完整复制和重新分配。
因此,例如,如果您有一个迭代 100 次的循环(10*x
和 10*y
总共 100 次)并且在每次迭代中它向字符串添加 50 个字符(因此最终输出长度为 5000 个字符),但它还会再次复制所有内容,所以一旦你超过了,比如说,1000 个字符,计算机现在每次都必须复制整个千字节 - 而你也通过复制 999、998、997、996 等字符到达那里 - 这的运行时复杂性非常糟糕(按 O(n^2)
的顺序)。
您可以这样做:
- (为简洁起见省略了外部
if
、try/catch
语句和 Logging
调用)
- 我看到您正在写入
Stream
,因此请使用具有所需编码集的 StreamWriter
。
- 我用
foreach
语句替换了你的 .ForEach
调用。
var tmp = LoadCellService.readFromExcel( LoadCellModel.LoadCellRowList.Where(x => x.Stage == 1 ).ToList() , 1 );
if (tmp.Item1 != null)
{
// This can be further optimized by loading `LoadCellModel.LoadCellRowList` into a dictionary by an appropriate key.
foreach( var z in tmp.Item1 )
{
var columnList = LoadCellModel.LoadCellRowList
.Where( x =>
x.Stage == z.Stage &&
x.RowIndex == z.RowIndex
)
.First();
columnList.LoadCellRowColumnList = z.LoadCellRowColumnList;
}
using( StreamWriter wtr = new StreamWriter( stream, Encoding.ASCII ) )
{
foreach( var x in LoadCellModel.LoadCellRowList )
{
foreach( var y in x.LoadCellRowColumnList.Where( yc => yc.LoadCellRowColumnKey == "Distance" ) )
{
wtr.Write( ';' );
wtr.Write( y.LoadCellRowColumnValue );
}
}
wtr.Flush();
}
}
else
{
byte[] msg = Encoding.ASCII.GetBytes("REQZ1E;\r");
stream.Write(msg, 0, msg.Length);
}
我在将字符串转换为字节数组时出现内存不足异常。
if (message.Contains("REQZ1S"))
{
string strMsg = "REQZID;";
try
{
var tmp = LoadCellService.readFromExcel(LoadCellModel.LoadCellRowList.Where(x => x.Stage == 1).ToList(), 1);
LogHelper.StartTo(nameof(LoadCellSiemensOPCModel), $"tmp count: {tmp.Item1.Count}");
if (tmp.Item1 != null)
{
tmp.Item1.ForEach(
z => LoadCellModel.LoadCellRowList.Where(x => x.Stage == z.Stage && x.RowIndex == z.RowIndex).First().LoadCellRowColumnList = z.LoadCellRowColumnList
);
LoadCellModel.LoadCellRowList.ForEach(
x => x.LoadCellRowColumnList.ForEach(y =>
{
LogHelper.StartTo("temp", y.LoadCellRowColumnKey + ";" + y.LoadCellRowColumnValue);
if (y.LoadCellRowColumnKey == "Distance")
{
strMsg += strMsg + ";" + y.LoadCellRowColumnValue;
}
})
);
LogHelper.KeyValue(nameof(LoadCellSiemensOPCModel), "message2", strMsg);
byte[] msg = System.Text.Encoding.ASCII.GetBytes(strMsg + "\r");
Stream.Write(msg, 0, msg.Length);
LogHelper.KeyValue(nameof(LoadCellSiemensOPCModel), "message", strMsg);
LogHelper.SiemensOPCTrace(nameof(LoadCellSiemensOPCModel), $"Write <<< {strMsg}");
}
else
{
byte[] msg = System.Text.Encoding.ASCII.GetBytes("REQZ1E;\r");
Stream.Write(msg, 0, msg.Length);
LogHelper.SiemensOPCTrace(nameof(LoadCellSiemensOPCModel), $"Write <<< REQZ1E;");
}
LogHelper.Done(nameof(LoadCellSiemensOPCModel), $"Write <<< REQZ1S;");
}
catch (Exception EX)
{
LogHelper.KeyValue(nameof(LoadCellSiemensOPCModel), "message1", strMsg);
LogHelper.Error("TEMP", EX);
}
}
我怀疑这部分还需要添加一些适当的逻辑:
byte[] msg = System.Text.Encoding.ASCII.GetBytes(strMsg + "\r");
Stream.Write(msg, 0, msg.Length);
问题不是 System.Text.Encoding.ASCII.GetBytes("REQZ1E;\r");
- 问题在这里:
LoadCellModel.LoadCellRowList.ForEach(
x => x.LoadCellRowColumnList.ForEach(y => {
// ...
strMsg += strMsg + ";" + y.LoadCellRowColumnValue;
// ...
}
使用 +=
运算符连接字符串 会导致整个字符串的完整复制和重新分配。
因此,例如,如果您有一个迭代 100 次的循环(10*x
和 10*y
总共 100 次)并且在每次迭代中它向字符串添加 50 个字符(因此最终输出长度为 5000 个字符),但它还会再次复制所有内容,所以一旦你超过了,比如说,1000 个字符,计算机现在每次都必须复制整个千字节 - 而你也通过复制 999、998、997、996 等字符到达那里 - 这的运行时复杂性非常糟糕(按 O(n^2)
的顺序)。
您可以这样做:
- (为简洁起见省略了外部
if
、try/catch
语句和Logging
调用) - 我看到您正在写入
Stream
,因此请使用具有所需编码集的StreamWriter
。 - 我用
foreach
语句替换了你的.ForEach
调用。
var tmp = LoadCellService.readFromExcel( LoadCellModel.LoadCellRowList.Where(x => x.Stage == 1 ).ToList() , 1 );
if (tmp.Item1 != null)
{
// This can be further optimized by loading `LoadCellModel.LoadCellRowList` into a dictionary by an appropriate key.
foreach( var z in tmp.Item1 )
{
var columnList = LoadCellModel.LoadCellRowList
.Where( x =>
x.Stage == z.Stage &&
x.RowIndex == z.RowIndex
)
.First();
columnList.LoadCellRowColumnList = z.LoadCellRowColumnList;
}
using( StreamWriter wtr = new StreamWriter( stream, Encoding.ASCII ) )
{
foreach( var x in LoadCellModel.LoadCellRowList )
{
foreach( var y in x.LoadCellRowColumnList.Where( yc => yc.LoadCellRowColumnKey == "Distance" ) )
{
wtr.Write( ';' );
wtr.Write( y.LoadCellRowColumnValue );
}
}
wtr.Flush();
}
}
else
{
byte[] msg = Encoding.ASCII.GetBytes("REQZ1E;\r");
stream.Write(msg, 0, msg.Length);
}