格式化日志输出具体方式
底层函数可以继续使用原来的方式,就是直接写字符串。由其它输出日志函数调用。
再写一个参数为XMLNODE的代理函数,此函数接受其它全部上层写日志函数的调用,上层函数将其日志格式全部统一,将信息放入XMLNODE中,然后由此代理调用底层函数写日志。
底层函数可以继续使用原来的方式,就是直接写字符串。由其它输出日志函数调用。
再写一个参数为XMLNODE的代理函数,此函数接受其它全部上层写日志函数的调用,上层函数将其日志格式全部统一,将信息放入XMLNODE中,然后由此代理调用底层函数写日志。
以往的几个系统都是使用一种比较随意的日志输出方式,就是有什么问题就输出,超时日志,错误日志,ASSERT,异常等全部在一个文件中,这样不方便查看,也不方便于对于紧急事件的反应;也无法控制输出级别,有些输出可能只在DEBUG版本或者第一个RELEASE版本才需要,当版本稳定后,就不需要这些日志了,日志级别应该全部是可以控制的。分两部分来谈这个问题:
1.可控级别:可控级别分在两个部位控制,第一个是编译级别,在编译级别中通过预编译参数或者宏来实现最高可输出级别,别一种是动态控制,使用参数来控制级别,只在小于参数值的级别才可以输出。编译级别的参数值优先级应该大于动态级别的,这样就可以方便显示控制日志输出量。
士兵突击有一次出现故障,就是因为同步服务把时间同步回去了,这样就造成当前时间可能会比内存中已经发现的事件的时间更早,一相减,是一个负数,因为我们使用的是DWORD,所以就变成一个很大的数目,造成数据异常。
解决办法:首先最好关掉服务器上的时间同步服务,然后对DWORD差值做检查,如果是负的,就不做操作,我认为使用DWORD要谨慎,在这上面出的问题不止一次了!
使用优先队列,元素为指针,如:
typedef priority_queue<TimeEvent*, deque <TimeEvent*>, less<deque<TimeEvent*>::value_type> TIME_EVENT_QUEUE;
这样比较的话,其结果是比较指针值,如果我要比较TimeEvent中的某个成员,就不行了,经过谷歌,可以采取一个方式,将less替换成一个结构的函数:
struct TimeEventLessComp
{
bool operator () (TimeEvent*& a, TimeEvent*& b) const
{
return a->dwTick > b->dwTick;
};
};
然后申明时改为:
typedef priority_queue<TimeEvent*, deque <TimeEvent*>, TimeEventLessComp> TIME_EVENT_QUEUE;
经过简单测试,生成500000个计时器,将指针分别插入list和priority_queue,其中priority_queue使用vector容器(不能使用list),先使用list自的sort函数,用时516ms,反复测了几次,都在500ms以上550ms以下 ,对priority_queue进行插入,在500000个的基础上,进行100000次插入,总用时31ms,平均每个0.00031ms
输出结果如下:
list sort time:516 ms
priority_queue push 100000 event use 31 ms time, average 0.000310 ms per event
sorted list sort time:516 ms
sorted list trace 0
sorted list trace 1
….
priority_queue trace 0
priority_queue trace 1
….
经过测试,优先队列明显性能高于LIST的自排序,很适合我的要求!
使用一个单向或者双向链表,或者使用一个优先队列(priority_queue).
队列中的元素为一个计时器对象。计时器对象包括,从标准时间(程序运行时)开始的时间差。越晚触发的计时器,这个值越大,及触发器事件类型。
如果只使用链表,每次插入后,就要进行一次重排,如果使用优先队列,自动插入顺序位置,我想使用优先队列应该效果好些,还要实验。
每次心跳(服务器线程循环),调用时间服务OnTicker函数,此函数检查队列中最前一个计时器的时间值,如果到达或者超过当前时间的时间差,就将此计时器取出,然后调用其触发器事件。
现在,有二个问题还未解答:
1.时间差值的精确程度,精确到什么程度?最好的情况是精确到微秒,那样,时间服务中的队列可能就会到几十万,这样对插入会有多大的影响,需要具体测试。
2.关于时间差的问题,以什么方式设置?目前使用的TICK是DWORD,32位,42亿多毫秒,换成天数是是49.71天,如果时间差直接放系统TICK+触发事件需要的时间,那么很可能会溢出。如果以程序运行时间为0点,且此时间点的系统TICK为SYSTEM_TICK,以此为参照,新加入的事件的时间值EVENT_TICK为:
EVENT_TICK = NOW_TICK(当前系统TICK) - SYSTEM_TICK+NEED_TIME(需要的时间),也就是说存放时有一个换算过程。这样最多可以存放离程序运行49天内的触发器。还没有考虑好