Idea - 小技巧tips
遇到的坑误踩。
使用技巧
组合而非继承,才是把C和C++结合在一起的唯一可行方法。
扩展接口,可以在函数后面新增参数,且通过给默认值的方式不影响原来老函数调用
变量未付初值,导致for循环异常。 ———— 字符串初始化为"",整数初始化为0
Linux服务器的sftp磁盘满时,会写入0kb的空文件
同质异步发现归并,对于查询相同的内容进行合并查询 ———— 思想就是归并相同的内容或等待积累一定量再定期查询
数据库连接池管理
流控限制,需要从网关侧统一考虑
代码灵活性,多用配置文件读取参数,或者就是从注册中心取
jsoncpp使用时,采用Json::FastWriter,压缩格式的json内容进行网络传输,传递时用压缩格式的 json 字符串,不包含没有必要的空格和换行符。
借助excel里的计算公式,例如将公式的字符串内容写到对应位置,关闭文件后再去读取excel的内容,已经是计算的结果了
同步比异步逻辑清晰;但是异步比同步速度快。
- 协程 ————> 异步的性能,同步的编码方式
- recv/send操作和epoll_wait在同一个流程,同步操作。
- recv/send操作和epoll_wait不在同一个流程,异步操作。
在真正需要一个存储空间时才去声明变量(分配内存),这样会得到程序在运行时最小的内存花销
异步消息: 不能发送地址,不同虚机地址里东西不一样
C++函数传递参数时,尽量不要多于6个,因为CPU寄存器有6个,大于6个时,程序需要压栈,影响效率!!
pubsub消息机制,不能确保消息一定被消费
- 消息先落地,然后异步处理,本地需要有个补偿的job,去处理本地消费失败的消息,这个可以参考push方式消费的过程。
tcmalloc优化内存使用。 内存碎片化问题解决,减少内核,用户态切换
Redis做热key缓存,根据QPS看是否要做集群,读写分离,如果是动态热key 。采用客户端,proxy代理redis的方式,让proxy做频率统计。
频繁打印io操作影响性能,需要控制printf的输出,利用函数统计来代替打印
利用头文件,cmake写自己的.h适配不同版本的头文件包含
根据ldd结果,拷贝需要的so文件 + busybox
在C或C++中,#和##是在宏定义中使用的两个特殊符号。
- #是字符串化操作符(stringize operator)。它用于将宏参数转换为字符串常量。
- ##是标记粘贴操作符(token-pasting operator)。它用于将多个标记(tokens)粘贴在一起形成一个新的标记
Dockerfile里面多一个命令会导致层级增加,且赋权会导致包含两次进程文件
通过nm查看符号表区分到底是C还是C++的编译结果
- nm ../deploy/stibel-init |grep user
c++编译器会将在extern "C"的大括号内部的代码当作C语言代码处理。所以很明显,上面的代码中,c++的名称修饰机制将不会起作用。
使用C++的宏“__cplusplus”判断当前编译单元是不是C++代码,实现平滑过渡
a.c:(.text+0x1c): undefined reference to `shared' ———— 链接时符号未定义
离散的思想,防止集中风暴,例如redis里的缓存集中失效,导致大量的请求来查数据库建立缓存
局部性原理:最近访问到的数据,它附近的数据近期也会被访问,所以操作系统层面会做预加载处理。
C++使用小技巧
- 使用C++library的 memcpy() 会更有效率:在C/C++标准库中,memcpy函数用于将一个内存区域的内容拷贝到另一个内存区域中。相比于使用循环逐个进行赋值操作(拷贝构造函数里赋值),使用memcpy函数能够实现更快的内存拷贝。这是因为:
- memcpy函数是标准库函数,由编译器进行优化,能够充分利用底层平台的指令集,完成内存拷贝操作,而循环赋值则需要使用多个指令逐个赋值,效率较低。
- memcpy函数可以利用CPU的并行处理能力,通过同时读取多个字节实现更快的内存拷贝,而循环赋值则无法充分利用CPU的并行处理能力。
- memcpy函数可以利用CPU的缓存机制,通过预读取数据提高内存访问效率,而循环赋值则需要频繁进行内存访问,容易造成CPU缓存失效,效率较低。
- 注意:如果存在virtual,memcpy()可以会改变编译器产生的内部members的初值,例如vptr。
- C++多态的主要用途是经由一个共同的接口来影响类型的封装
- 使用emplace替换insert或push_back操作(创建局部临时对象,将其压入容器中 ————> 在容器管理的内存空间中直接创建对象)
- 类的指针成员,需要使用深拷贝,避免浅拷贝带来的重复析构和内存泄漏
- inline是C++关键字,在函数声明或定义中,函数返回类型前加上关键字inline,即可以把函数指定为内联函数。这样可以解决一些频繁调用的函数大量消耗栈空间(栈内存)的问题。
- 引用限定符可以是&或&&
- 当模板被使用时才能进行实例化,相同的实例可能出现在多个对象文件中。 ———— 通过显示实例化来避免这种开销
- using声明和using指示
- using声明一次之引入命名空间中的一个成员。
- using指示使得某个特定的命名空间中所有的名字都可见。
- 头文件与using声明或者using指示
- using声明和using指示会将名字注入到所有包含该头文件的文件中,而头文件应该只负责定义接口部分的名字,而不定义实现部分的名字。因此,通常情况下,头文件最多只在函数(local)作用域或namespace内使用using声明或指示。
- 注意: 在头文件中,尽量避免using指示,因为using指示会引入指定命名空间内所有成员名字,从而污染所有include该头文件的文件。
- 运行时类型识别:类型含有虚函数时,运算符将使用指针或引用所绑定对象的动态类型。
- typeid 运算符,用于返回表达式的类型
- dynamic_cast 运算符,用基类指针或引用安全地转换成派生类的指针或引用
- 枚举类型: 限定作用域和不限定作用域
- x86下Linux支持的系统调用参数至多6个,分别使用6个寄存器为传递,它们分别是EBX\ECX\EDX\ESI\EDI\EBP。
- 函数级别链接
- GCC编译器也提供了类似的机制,它有两个选择分别是“-ffunction-sections”和“-fdata-sections”,这两个选项的作用就是将每个函数或变量分别保持到独立的段中
C使用小技巧
- errno: 多线程并发时,A线程的errno获取之前可能被B线程覆盖
- printf/fprintf: 流输出函数是线程不安全的,共享同一个控制台或文件输出。使用临界区或者加锁方式。
- 静态运行库里面一个目标文件只包含一个函数
- printf.o只有printf()函数、strlen.o只有strlen()函数
- 链接器在链接静态库的时候是以目标文件为单位的, 可以减少最终生成可执行文件的大小
- 使用指针数组而不是二维数组:是因为更加节省空间。
认知
- 项目:需求分析,设计思想最重要,先构思,再功能。** ———— 先写入值,从转换从数据库查等
- 学习技术, 理解大于一切
- 基于API契约将松耦合服务组合成产品
BUG
- 使用公共库时,如果环境上存在两个同名库,可能引起链接时失败,找不到定义,定位一下原因,是不是搜索库顺序。最好删除其中一个库
- 互斥锁的异常场景释放,可能新增的else if条件判断里异常没有释放锁,尽量成对使用