esp8266接收到的数据如何存放到数组中_C中谁最快:结构还是类?

(给DotNet加星标,提升.Net技能)

转自: androllen cnblogs.com/luquanmingren/p/11263161.html

前言

在内存当道的日子里,无论什么时候都要考虑这些代码是否会影响程序性能呢?

在现在的世界里,几乎不会去考虑用了几百毫秒,可是在特别的场景了,往往这几百毫米确影响了整个项目的快慢。

通过了解这两者之间的性能差异,希望帮助大家在合适的场景里选择正确的编码。

实例

public class PointClass
{
public int X { get; set; }
public int Y { get; set; }
public PointClass(int x, int y){
X = x;
Y = y;
}
}
public class PointClassFinalized : PointClass
{
public PointClassFinalized(int x, int y) : base(x, y){
}
~PointClassFinalized()
{
// added a finalizer to slow down the GC
}
}

public struct PointStruct
{
public int X { get; set; }
public int Y { get; set; }
public PointStruct(int x, int y){
X = x;
Y = y;
}
}

public class StructsTest : PerformanceTest
{
protected override bool MeasureTestA(){
// access array elements
var list = new PointClassFinalized[Iterations];
for (int i = 0; i < Iterations; i++)
{
list[i] = new PointClassFinalized(i, i);
}
return true;
}

protected override bool MeasureTestB(){
// access array elements
var list = new PointClass[Iterations];
for (int i = 0; i < Iterations; i++)
{
list[i] = new PointClass(i, i);
}
return true;
}
protected override bool MeasureTestC(){
// access array elements
var list = new PointStruct[Iterations];
for (int i = 0; i < Iterations; i++)
{
list[i] = new PointStruct(i, i);
}
return true;
}
}

有一个PointClass和一个 PointStruct,这两者用于存放X 和Y 两个变量,而且还有一个 PointClassFinalized。

方法 MeasureTestA 创建了100万个 PointClassFinalized 实例

方法 MeasureTestB 创建了100万个 PointClass 实例

方法 MeasureTestC 创建了100万个 PointStruct 实例

您认为哪种方法最快?

edb67406064c8ea5e52390be38a1a822.png

MeasureTestB 和 MeasureTestC 这两个方法的唯一不同在于一个是创建类 一个是创建结构。

MeasureTestC 仅在17毫秒内完成分配并运行,比 MeasureTestB 方法快8.6倍!

为什么会出现这样的事情,这里发生了什么?

不同的在于结构和类如何存储在内存中。

下面是 PointClass 实例 内存布局:

53738b8d2734b65675371c6859618510.png

该列表是一个局部变量,存放在堆栈中。引用堆上的一组 PointClass实例

PointClass 是一个引用类型,存放在堆上。

该列表仅维护一个数组,指向存储在堆上 PointClass 实例。

观察到上图的黄色箭头,在堆上引用了很多实例。

数组是一组相同的对象,MeasureTestB 这个方法是将一组相同的对象存放在数组中。

当访问指定数组元素时,.NET运行时需要检索对象引用,然后“跟随”引用以获取PointClass实例。

当数组元素超出范围时,.NET垃圾收集器就会开始回收PointClass对象内存,在 MeasureTestA 方法中 的PointClassFinalized类 其实增加了额外时间。

.NET Framework在单个线程上运行所有终结器,线程必须在垃圾回收器可以回收内存之前依次处理1,000,000个对象。

可以看到MeasureTestA比MeasureTestB慢1.7倍。

我们来看看 PointStruct 的内存布局:

dfcbd3021d48c473097589e001bd24aa.png

结构是值类型,所有 PointStruct 实例都存储在数组本身中。堆上只有一个对象。

初始化数组,.NET运行库可以将X和Y值直接写入数组里。无需在堆上创建新对象,也不需要引用它。

当访问指定数组元素时,.NET运行时可以直接检索结构。

当超出范围时,.NET垃圾回收器只需要处理单个对象。

总结

我们总要使用结构吗?要分情况看:

  • 当您存储超过30-40个字节的数据时,请使用类。

  • 存储引用类型时,请使用类。

  • 当您存储多于几千个实例时,请使用类。

  • 如果列表是长的生命周期的,请使用类。

  • 在所有其他情况下,使用结构。

推荐阅读

(点击标题可跳转阅读)

C#一句很简单而又很经典的代码

ASP.NET Core Web API使用小技巧

ASP.NET Core 中的管道机制

看完本文有收获?请转发分享给更多人

关注「DotNet」加星标,提升.Net技能 

e51faed83e1391e7ef8fd13a911cbbb7.png

好文章,我在看❤️

ESP8266 接收数据保存到数组中通常涉及以下几个步骤: 1. **初始化接收缓冲区**:ESP8266 收到数据首先会被存储在一块内部接收缓冲区内。你需要预留足够的空间来存放可能接收到的完整数据。 2. **设置断或事件监听**:ESP8266 通过硬件或软件(如 Lua 或 MicroPython)可以配置接收数据时触发断,这样程序可以在接收数据时立即处理。 3. **读取和拼接数据**:当接收数据时,你可以从缓冲区读取一小段,并将其添加到数组中。这可能需要循环进行直到所有数据都读完。 4. **分隔和解析数据**:如果接收到的是带分隔符(例如换行符 `\n`)的数据,你需要对每一部分进行分割,再逐个添加到数组里。 5. **数组操作**:确保你在添加数据时不会超过数组大小,必要时可以动态调整数组长度,或者使用链表等数据结构来避免这个问题。 示例代码(假设我们正在使用 Arduino IDE 的 C++): ```cpp char receiveBuffer[100]; // 初始化接收缓冲区 String data; String arrayData[]; // 创建用于保存的数组 void onDataReceived(char* incomingData) { int index = 0; while (index < sizeof(receiveBuffer) && incomingData[index] != '\0') { receiveBuffer[index++] = incomingData[index]; } receiveBuffer[index] = '\0'; // 添加终止符 if (receiveBuffer == "some_expected_data") { // 数据分隔判断 data += receiveBuffer; arrayData.push_back(data); // 将数据添加到数组 data.clear(); // 清空接收缓冲区 } } // ... 在合适的地方注册接收数据的回调函数 ``` 记得根据实际数据格式和协议定制相应的逻辑。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值