0.前言
俗话说“听君一席话,胜读十年书”,在项目执行过程中有幸同一位大神进行了一次交流。收获良多,特记录于此,以供后参。
1.使用柔性数组
在C99标准中,添加了一个新特性——柔性数组:
typedef struct
{
int len;
char buf[0];
}SOFT_ARR,*SOFT_ARR_PTR;
上述结构体类型SOFT_ARR中的成员buf即为柔性数组。其中,sizeof(SOFT_ARR)的结果为4,表明结构体成员buf并未占用内存空间。
可以按照如下两种方式使用柔性数组:
- 方式1:动态分配内存
#define MAX_DATA_LEN 10
SOFT_ARR_PTR sa=(SOFT_ARR_PTR)malloc(sizeof(SOFT_ARR)+MAX_DATA_LEN);
- 方式2:静态分配内存 10
#define MAX_DATA_LEN
char buf[sizeof(SOFT_ARR)+MAX_DATA_LEN]={0};
SOFT_ARR_PTR sa=(SOFT_ARR_PTR)buf;
在这两种使用方式下,sa.data的长度均为10,区别在于内存空间的分配方式。这就引出如下三个原则。
2.三个原则
(1) 少使用malloc函数:频繁使用malloc会导致内存碎片的产生,且不易于管理。
(2)少使用memcpy函数:memcpy函数会增加程序执行时间,应多使用指针赋值操作,且应采用指针累加偏移,而不是数组累乘以提升效率。(乘法指令执行时间大于加法指令)。
(3)少锁:在多线程环境下,减少锁的使用,或尽可能降低锁的粒度。
3.大数据量的多线程处理
类似于使用UDP传输的音视频数据,在进行处理时应首先使用一个线程专门负责接收数据,并将其存入缓冲区中(工作队列(链表))。然后另外使用一个或多个线程负责从缓冲区中取出数据并进行处理。这里除了多线程处理之外,还涉及到如下两个要点。
4.工作队列与空闲队列
处理过程中所使用的缓冲区应该分为工作队列与空闲队列(在操作系统内核中有大量使用这种方式)。初始化时仅为空闲队列分配好空间,在实际处理的过程中,实时地从空闲队列(链表)中取下一个节点加入到工作队列中。之后,工作队列处理完一个节点后,将该节点归还到空闲队列中。这样做的好处是预分配空间后可在程序运行过程中减少malloc与free的次数,而且所有操作均可使用指针操作完成,可以提升程序的执行效率。
5.总结
对于大数据量的快速处理需求,可以采用如下模式:
UDP+柔性数组+多线程+工作队列