stdext Relation: 数据表(DataTable)

stdext Relation: 数据表(DataTable)

许式伟
2008-7-22

Relation容器简介

Relation是一个复杂容器。简单来说,它是一个数据表(DataTable)。它类似于数据库(Database)中的表,当然,是一个简化的表:简化在于没有复杂的SQL语句,只是支持基于关键字(索引)的select。

应用场景:如果你的数据有多列,并且需要相互查找(多对多关系),那么Relation容器非常适合。

著名的GLib(GNOME Library)有一个GRelation,和stdext Relation的功能类似。但stdext Relation的功能更加强大。这表现在:

  • stdext的Relation是真正的数据表(DataTable),可以创建任意多列的数据,而不只是2列。创建2列的表,可以使用stl的std::pair(当然也可以用boost::tuple)。创建超过2列的表,使用boost::tuple。
  • 可以为任意列创建索引,并且各列独立指定使用map(红黑树)还是hash map(哈希表)作为索引表是可能的。
  • 可以为若干列创建联合主键,使得这些列联合的数据不会重复。

Relation简单样例

下面是一个Relation的样例。为了简单,该例是2列的表,并且所有列都用hash map作为索引。这个样例可以在 stdext/examples/relation/Simplest.cpp 中找到。

typedef std::AutoFreeAlloc AllocT;
typedef std::pair<std::string, int> TupleT;
typedef std::Relation<TupleT, 3, 0, std::HashMapIndexing, AllocT> RelationT;
typedef RelationT::Indexing<0> Indexing0;
typedef RelationT::Indexing<1> Indexing1;

AllocT alloc;
RelationT rel(alloc);

rel.insert(TupleT("Mon", 1));
rel.insert(TupleT("Monday", 1));
rel.insert(TupleT("Tue", 2));
rel.insert(TupleT("Wed", 3));
rel.insert(TupleT("Wednesday", 3));
AssertExp(rel.size() == 5);

Indexing1::range rg = rel.select<1>(3);
AssertExp(std::distance(rg.first, rg.second) == 2);
for (Indexing1::iterator it = rg.first; it != rg.second; ++it) {
const TupleT& i = Indexing1::item(it);
AssertExp(i.first == "Wed" || i.first == "Wednesday");
AssertExp(i.second == 3);
}

Indexing0::range rg2 = rel.select<0>("Mon");
AssertExp(std::distance(rg2.first, rg2.second) == 1);
Indexing0::iterator it2 = rg2.first;
const TupleT& i2 = Indexing0::item(it2);
AssertExp(i2.first == "Mon" && i2.second == 1);

AssertExp(rel.count<1>(1) == 2);
AssertExp(rel.erase<1>(1) == 2);
AssertExp(rel.count<1>(1) == 0);
AssertExp(rel.size() == 3);

Indexing0::range rg3 = rel.select<0>("Mon");
AssertExp(std::distance(rg3.first, rg3.second) == 0);
AssertExp(rel.count<0>("Monday") == 0);

Relation 更多样例…

如果这不满足你的需求,我们还有一些更为复杂的样例(同样,这些样例在 stdext/examples/relation/Simplest.cpp 中可以找到):

testCustomIndexing

这个样例展示了如何定制索引。

// Field 0: rb-tree indexing
// Field 1..(N-1): hash-table indexing

即第0列使用rb-tree(红黑树),其他列用hash表做索引。

testTupleRelation

支持多列的样例(使用了boost::tuple)。

stdext Relation vs. GRelation(GLib)性能对比

测试程序: stdext/performance/relation/Performance.cpp

主要比较两个操作:插入(insert)与查找(select)。注:如果你取最新的代码,stdext Relation的表现应该会更好,这是因为我再次做了优化,但是没有更新这里的测试数据。

插入(insert)的对比结果

===== GRelation (insert) =====
---> Elapse 37163475 ticks (37.16 ms) (0.00 min) ...
---> Elapse 38908908 ticks (38.91 ms) (0.00 min) ...
---> Elapse 37951608 ticks (37.95 ms) (0.00 min) ...
---> Elapse 38112183 ticks (38.11 ms) (0.00 min) ...
---> Elapse 38991814 ticks (38.99 ms) (0.00 min) ...
---> Elapse 37209503 ticks (37.21 ms) (0.00 min) ...
---> Elapse 37091604 ticks (37.09 ms) (0.00 min) ...
---> Elapse 38056097 ticks (38.06 ms) (0.00 min) ...
---> Elapse 37491538 ticks (37.49 ms) (0.00 min) ...
---> Elapse 37197071 ticks (37.20 ms) (0.00 min) ...
---> Elapse 36716046 ticks (36.72 ms) (0.00 min) ...
---> Elapse 35923233 ticks (35.92 ms) (0.00 min) ...
---> Elapse 36989910 ticks (36.99 ms) (0.00 min) ...
---> Elapse 36041970 ticks (36.04 ms) (0.00 min) ...
---> Elapse 37710083 ticks (37.71 ms) (0.00 min) ...
---> Elapse 38065317 ticks (38.07 ms) (0.00 min) ...
Average: ---> Elapse 37476272 ticks (37.48 ms) (0.00 min) ...

===== Relation (insert) =====
---> Elapse 7990647 ticks (7.99 ms) (0.00 min) ...
---> Elapse 8297058 ticks (8.30 ms) (0.00 min) ...
---> Elapse 9548964 ticks (9.55 ms) (0.00 min) ...
---> Elapse 8238109 ticks (8.24 ms) (0.00 min) ...
---> Elapse 8142560 ticks (8.14 ms) (0.00 min) ...
---> Elapse 8000914 ticks (8.00 ms) (0.00 min) ...
---> Elapse 7674457 ticks (7.67 ms) (0.00 min) ...
---> Elapse 7784394 ticks (7.78 ms) (0.00 min) ...
---> Elapse 8068944 ticks (8.07 ms) (0.00 min) ...
---> Elapse 7860595 ticks (7.86 ms) (0.00 min) ...
---> Elapse 7785512 ticks (7.79 ms) (0.00 min) ...
---> Elapse 8525382 ticks (8.53 ms) (0.00 min) ...
---> Elapse 7681512 ticks (7.68 ms) (0.00 min) ...
---> Elapse 7877846 ticks (7.88 ms) (0.00 min) ...
---> Elapse 7896565 ticks (7.90 ms) (0.00 min) ...
---> Elapse 7597069 ticks (7.60 ms) (0.00 min) ...
Average: ---> Elapse 8060658 ticks (8.06 ms) (0.00 min) ...

查找(select)的对比结果

===== GRelation (select) =====
---> Elapse 18511577 ticks (18.51 ms) (0.00 min) ...
---> Elapse 15667689 ticks (15.67 ms) (0.00 min) ...
---> Elapse 16131391 ticks (16.13 ms) (0.00 min) ...
---> Elapse 15866818 ticks (15.87 ms) (0.00 min) ...
---> Elapse 15679213 ticks (15.68 ms) (0.00 min) ...
---> Elapse 16461061 ticks (16.46 ms) (0.00 min) ...
---> Elapse 15717209 ticks (15.72 ms) (0.00 min) ...
---> Elapse 16135303 ticks (16.14 ms) (0.00 min) ...
---> Elapse 15502853 ticks (15.50 ms) (0.00 min) ...
---> Elapse 16177000 ticks (16.18 ms) (0.00 min) ...
---> Elapse 15647992 ticks (15.65 ms) (0.00 min) ...
---> Elapse 15948956 ticks (15.95 ms) (0.00 min) ...
---> Elapse 15846702 ticks (15.85 ms) (0.00 min) ...
---> Elapse 15622359 ticks (15.62 ms) (0.00 min) ...
---> Elapse 16597469 ticks (16.60 ms) (0.00 min) ...
---> Elapse 15605666 ticks (15.61 ms) (0.00 min) ...
Average: ---> Elapse 16069953 ticks (16.07 ms) (0.00 min) ...

===== Relation (select) =====
---> Elapse 3047628 ticks (3.05 ms) (0.00 min) ...
---> Elapse 3125855 ticks (3.13 ms) (0.00 min) ...
---> Elapse 2869383 ticks (2.87 ms) (0.00 min) ...
---> Elapse 2919881 ticks (2.92 ms) (0.00 min) ...
---> Elapse 3014382 ticks (3.01 ms) (0.00 min) ...
---> Elapse 2921627 ticks (2.92 ms) (0.00 min) ...
---> Elapse 2875459 ticks (2.88 ms) (0.00 min) ...
---> Elapse 2843331 ticks (2.84 ms) (0.00 min) ...
---> Elapse 3197377 ticks (3.20 ms) (0.00 min) ...
---> Elapse 2871687 ticks (2.87 ms) (0.00 min) ...
---> Elapse 2821260 ticks (2.82 ms) (0.00 min) ...
---> Elapse 3263100 ticks (3.26 ms) (0.00 min) ...
---> Elapse 2905074 ticks (2.91 ms) (0.00 min) ...
---> Elapse 2855135 ticks (2.86 ms) (0.00 min) ...
---> Elapse 3093517 ticks (3.09 ms) (0.00 min) ...
---> Elapse 2958995 ticks (2.96 ms) (0.00 min) ...
Average: ---> Elapse 2973980 ticks (2.97 ms) (0.00 min) ...

为什么stdext Relation 比 GRelation 好这么多?

其实两者的实现方案完全类似。唯一不同是而GLib多了一个我认为不必要的HashTable,这导致GLib在插入时多了一次多余的查找(但 select性能不会因为这个多余的HashTable影响)。但是就这一点而言,怎么也不致于差这么多:你可以看到两者性能差5倍左右。

这个例子很典型。那些认为C比C++更容易写出高效的代码的人应该想想性能差异主要在哪些地方。

其实我认为关键的性能差异(之一)在于C用了回调(callback),C++用了仿函数(functor)

这个问题在sort函数上更为明显,因为sort中比较函数调用非常频繁,比HashTable要频繁很多。

所以,C++的std::sort的性能是任何语言都无法与之相提并论的。关于仿函数(functor)更详细的信息,参阅:http://cpp.winxgui.com/cn:functor

 
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 8
    评论
### 回答1: 以下是一个设置CAN通道发送周期和ID的例子: ``` #include <mcp_can.h> #include <SPI.h> MCP_CAN CAN(10); // 定义一个CAN对象,使用引脚10作为CS引脚 void setup() { Serial.begin(9600); while (!Serial); // 等待串口连接 // 初始化CAN总线 if (CAN.begin(MCP_STDEXT, CAN_500KBPS, MCP_16MHZ) == CAN_OK) { Serial.println("CAN初始化成功"); } else { Serial.println("CAN初始化失败"); } } void loop() { // 定义一个CAN帧 unsigned char data[8] = {0, 1, 2, 3, 4, 5, 6, 7}; unsigned char len = sizeof(data); unsigned long canId = 0x123; // 设置发送周期为100ms unsigned long sendPeriod = 100; // 发送CAN帧 CAN.sendMsgBuf(canId, 0, len, data); Serial.print("发送CAN帧:"); for (int i = 0; i < len; i++) { Serial.print(data[i], HEX); Serial.print(" "); } Serial.println(); // 等待发送周期结束 delay(sendPeriod); } ``` 这个例子使用MCP_CAN库,通过定义一个CAN对象,可以对CAN总线进行初始化并发送CAN帧。在这个例子中,我们定义了一个CAN帧的数据和ID,然后设置了发送周期为100ms,每隔100ms发送一次CAN帧。注意,这个例子中的CAN ID是固定的,如果需要改变CAN ID,可以修改`canId`变量的值。 ### 回答2: CAN(Controller Area Network)是一种用于在不同设备之间进行通信的串行总线系统。在CAN通信中,每个设备(节点)都通过发送消息(数据帧)来进行通信。 设置CAN通道的发送周期和ID,可以通过以下示例进行说明: 假设我们有一个基于CAN的汽车电子控制系统,其中包括发动机控制单元、传感器和执行器。我们想要设置一个CAN通道来发送发动机转速的信息。 首先,我们需要确定发送周期。在这个例子中,我们可能希望每秒钟发送一次发动机转速的信息。我们将这个发送周期设置为1秒,以确保我们能够即时地接收到发动机转速的更新。 接下来,我们需要确定消息的ID。在CAN通信中,每个消息都有一个唯一的标识符,称为ID。这个ID用于区分不同的消息,并帮助接收方将消息与特定的功能关联起来。在这个例子中,我们可以选择一个任意的ID,比如100。 通过设置ID为100和发送周期为1秒,我们可以将这个CAN通道配置为定期发送发动机转速信息给其他节点。当其他的节点接收到这个消息时,它们可以解码该消息并执行相应的操作,比如调整油门位置或者记录数据。 总之,通过设置CAN通道的发送周期和ID,我们可以定期发送特定的信息给其他设备,以实现各种功能和控制操作。在具体的应用中,根据系统需求和通信协议的规定,我们可以灵活地配置CAN通道的发送周期和ID。 ### 回答3: CAN通道的发送周期和ID的设置可以通过以下示例来说明。 假设我们有一辆汽车,通过CAN总线与不同的设备进行通信。在CAN总线上,我们可以设置不同的发送周期和ID来控制消息的发送和接收。 首先,我们可以设置一个发送周期来定时发送特定的消息。比如,我们可以设置一个周期为100毫秒的发送周期。这意味着每100毫秒,我们的汽车将发送一次特定的消息到CAN总线上。 其次,我们可以设置不同的ID来区分不同的消息。例如,我们可以设置ID为0x100的消息用于发送车速数据,ID为0x200的消息用于发送引擎温度数据,ID为0x300的消息用于发送转向灯状态等等。通过设置不同的ID,我们可以使接收方能够根据ID来识别和处理不同的消息。 例如,我们可以设置车速数据的发送周期为100毫秒,ID为0x100。这意味着每隔100毫秒,汽车将发送一次ID为0x100的车速数据消息到CAN总线。接收方可以根据这个ID来识别这是一条车速数据消息,并进行相应的处理,如显示在仪表盘上。 另外,我们还可以设置引擎温度数据的发送周期为200毫秒,ID为0x200。这样,每隔200毫秒,汽车将发送一次ID为0x200的引擎温度数据消息到CAN总线上。接收方可以根据这个ID来识别这是一条引擎温度数据消息,并根据实际情况进行相应的控制,如发出警报或采取其他适当的措施。 总之,通过设置CAN通道的发送周期和ID,我们可以实现定时发送特定消息并且能够使用ID来区分和处理不同的消息。这样,我们可以有效地控制和监控汽车系统中的各种信息。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 8
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值