[C] 延迟限速逻辑
作者:互联网
把一个函数放到一个循环中,这个函数被调用的频率在一定程度上反映了程序的速度。
while(任务没有全部完成)
{
完成一段任务
获得程序执行速度
if(程序执行速度 > 程序执行速度的上限)
限速
}
1.需要一个标准判断程序执行速度
2.每一次调用函数时都获得程序执行速度并判断可能浪费性能
因此改为
while(任务没有全部完成)
{
完成一段任务
++检测程序速度的间隔所占的函数调用历史次数
if(检测程序速度的间隔所占的函数调用历史次数 >= 检测延迟的间隔所占的函数调用次数的理想值)
{
获得程序执行速度
if(程序执行速度 > 程序执行速度的上限)
{
限速
检测程序速度的间隔所占的函数调用历史次数 = 0
}
}
}
把计算程序执行速度的具体逻辑代入:
while(任务没有全部完成)
{
完成一段任务
// 参数初始化
if(没有初始化)
获取系统时间
// 更新参数
++检测程序速度的间隔所占的函数调用历史次数
// 检测程序速度
if(检测程序速度的间隔所占的函数调用历史次数 >= 检测延迟的间隔所占的函数调用次数的理想值)
{
// 更新参数
获取系统时间
检测程序速度的间隔所占的时间 = 该次获得的系统时间 - 最近一次获得的系统时间
程序执行速度 = 检测程序速度的间隔所占的函数调用历史次数/检测程序速度的间隔所占的时间
// 限速主体逻辑
if(程序执行速度 > 程序执行速度的上限)
{
限速
检测程序速度的间隔所占的函数调用历史次数 = 0
}
}
}
至此逻辑还是很简单,但是,转换成代码时还需要考虑一些问题
比如,使用这段代码的人怎么确定“程序执行速度的上限”?如果我只能赋“程序执行速度的上限”为一个根据经验摸索出来的数值,那么这个程序的通用性是很差的,不同的人,有不同的经验。因此需要找到一个通用的标准衡量这个上限。
由于我们使用“程序执行速度 = 检测程序速度的间隔所占的函数调用历史次数/检测程序速度的间隔所占的时间”来定义“程序执行速度”,所以可以规定单位时间内程序执行的次数作为上限,把这个规定代入:
while(任务没有全部完成)
{
完成一段任务
// 参数初始化
if(没有初始化)
获取系统时间
// 更新参数
++检测程序速度的间隔所占的函数调用历史次数
// 检测程序速度
if(检测程序速度的间隔所占的函数调用历史次数 >= 检测延迟的间隔所占的函数调用次数的理想值)
{
// 更新参数
获取系统时间
检测程序速度的间隔所占的时间 = 该次获得的系统时间 - 最近一次获得的系统时间
程序执行速度 = 检测程序速度的间隔所占的函数调用历史次数/检测程序速度的间隔所占的时间
// 限速主体逻辑
if(程序执行速度 > 检测程序速度的间隔所占的函数调用理想次数/单位时间)
{
限速
检测程序速度的间隔所占的函数调用历史次数 = 0
}
}
}
这里引入了一个“检测程序速度的间隔所占的函数调用理想次数”,代表了代码使用者期望的“程序执行速度的上限”
再往下看,要真正起到限速的作用,只能让程序等待一段时间。速度和时间是不同的量度,我们还需要使用“等待”具体实现“限速”。
如果需要限速,怎么知道我应该“等待”多久?实际程序执行越快,限速就应该越狠,因此“等待”时间的大小与实际与理想的速度差有关,即
等待时间 = 速度差 * 单位时间
代入:
while(任务没有全部完成)
{
完成一段任务
// 参数初始化
if(没有初始化)
获取系统时间
// 更新参数
++检测程序速度的间隔所占的函数调用历史次数
// 检测程序速度
if(检测程序速度的间隔所占的函数调用历史次数 >= 检测延迟的间隔所占的函数调用次数的理想值)
{
// 更新参数
获取系统时间
检测程序速度的间隔所占的时间 = 该次获得的系统时间 - 最近一次获得的系统时间
程序执行速度 = 检测程序速度的间隔所占的函数调用历史次数/检测程序速度的间隔所占的时间
// 限速主体逻辑
if(程序执行速度 > 检测程序速度的间隔所占的函数调用理想次数/单位时间)
{
等待((程序执行速度 - 检测程序速度的间隔所占的函数调用理想次数/单位时间) * 单位时间)
检测程序速度的间隔所占的函数调用历史次数 = 0
}
}
}
考察这一段代码的时间复杂度,“完成一段任务”不需要我们担心,所以我们唯一可能优化的就是从 if(检测程序速度的间隔所占的函数调用历史次数 >= 检测延迟的间隔所占的函数调用次数的理想值) 开始的这一段:它是否在每次循环中都会判定为真?或者说,检测程序速度是否会过于频繁?
现在代码使用者已经清晰地知道自己能够控制的参数的物理意义,但即使如此,代码使用者不一定能够确定好一个合适的“检测延迟的间隔所占的函数调用次数的理想值”,也就是说,如果理想值过小,检测程序速度可能会过于频繁,我们需要尽量避免这个情况。
既然已经开始考虑了理想值的大小,那么就应该开始分类讨论了:
①“检测延迟的间隔所占的函数调用次数的理想值”设置合理
②“检测延迟的间隔所占的函数调用次数的理想值”设置不合理
什么是合理的理想值?就是使得检测程序速度的频率适中的值。什么是检测程序速度的频率适中?就是尽量避免程序“超速”,但是又不能太极端,比如令“检测延迟的间隔所占的函数调用次数的理想值”=1,为了防止“超速”而执行一次任务就检测一次速度。
程序运行速度因机而异,因时而异,但总的来说,可以认为它可以在某一段时间内保持不变,某一时刻,程序运行速度发生变化,接着稳定在另一段时间内,这是一个阶梯状的分段函数,因此我们只需要对分段函数做两步操作,一个是速度平缓时,一个是速度突变时。操作之后,我们希望速度被钳制到一个上限,也就是说,速度平缓时,钳制这个速度到理想值。
速度平缓用什么衡量?速度突变用什么衡量?要是真的用什么统计学的话……emmm,或许也不是不行,但是最简单的来说,只需要判断这一次单位时间“所占的函数调用历史次数”和最近一次单位时间“所占的函数调用历史次数”之间的关系就好了。
while(任务没有全部完成)
{
完成一段任务
// 参数初始化
if(没有初始化)
获取系统时间
// 更新参数
++检测程序速度的间隔所占的函数调用历史次数
// 检测程序速度
if(检测程序速度的间隔所占的函数调用历史次数 >= 检测延迟的间隔所占的函数调用次数的理想值)
{
// 更新参数
获取系统时间
检测程序速度的间隔所占的时间 = 该次获得的系统时间 - 最近一次获得的系统时间
程序执行速度 = 检测程序速度的间隔所占的函数调用历史次数/检测程序速度的间隔所占的时间
// 限速主体逻辑
if(程序执行速度 > 检测程序速度的间隔所占的函数调用理想次数/单位时间)
{
等待((程序执行速度 - 检测程序速度的间隔所占的函数调用理想次数/单位时间) * 单位时间)
检测程序速度的间隔所占的函数调用历史次数 = 0
}
}
// 参数初始化
if(没有初始化)
最近一次单位时间所占的函数调用历史次数 = 0
// 更新参数
获取系统时间
调整理想值的累计时间间隔 = 该次获得的系统时间 - 最近一次获得的系统时间
// 调整理想值主体逻辑
if(调整理想值的累计时间间隔 == 一个单位时间)
{
获取这一次单位时间所占的函数调用历史次数
if(abs(这一次单位时间所占的函数调用历史次数 - 最近一次单位时间所占的函数调用历史次数) > 速度浮动限度)
调整检测程序速度的间隔所占的函数调用理想次数
调整理想值的累计时间间隔 = 0
}
}
嗯……写累了
以上就是我看到那个限速的代码之后全部的思路了,中文伪代码看着多,写起来容易。但是实际上那个限速的代码更容易,因为他是把限速主体逻辑和调整理想值主体逻辑耦合在一起的
// 更新参数
++检测限速的间隔所占的函数调用历史次数
// 检测限速
if(检测限速的间隔所占的函数调用次数的历史值 >= 检测限速的间隔所占的函数调用次数的理想值)
{
// 更新参数
获取系统时间
检测限速所占的时间间隔 = 该次获得的系统时间 - 最近一次获得的系统时间
// 限速逻辑主体
if(检测限速所占的时间间隔 <= 规定限速时间) // 速度太快,需要限速
{
//
if(检测限速的间隔所占的函数调用次数的历史值 >= 给定的检测限速的间隔所占的函数调用次数的理想值)
{
检测限速的间隔所占的函数调用次数的理想值 = 检测限速的间隔所占的函数调用次数的历史值
等待(单位时间 - 检测限速所占的时间间隔)
// 重置参数
获取系统时间
检测限速的间隔所占的函数调用次数的历史值 = 0
}
}
else
{
检测限速的间隔所占的函数理想调用次数减小 // 减小规则可以参考 检测限速的间隔所占的函数理想调用次数/规定限速时间 = 检测限速的间隔所占的函数调用历史次数/该次检测限速所占的时间间隔
// 重置参数
检测限速的间隔所占的函数调用次数的历史值 = 0
}
}
源代码
/*=============================================================================
#
# Author: DanteZhu - dantezhu@vip.qq.com
#
# QQ: 327775604
#
# Last modified: 2009-12-21 13:33
#
# Filename: timelimit.h
#
# Description: �ٶ�������
#
=============================================================================*/
#ifndef _TIME_LIMIT_H_
#define _TIME_LIMIT_H_
#include <sys/time.h>
class CTimeLimit
{
public:
CTimeLimit()
{/*{{{*/
Clear();
}/*}}}*/
/**
* @brief ��ʼ��
*
* @param iMaxCount ����ٶ�
*
*/
void Init(int iMaxCount)
{/*{{{*/
m_MaxCount=iMaxCount;
m_TrueMaxCount=iMaxCount;
}/*}}}*/
/**
* @brief �����ٶ�
*
* @return 0,1,2,3
*/
int DetectAndLimit()
{/*{{{*/
if(!m_Run)
{
m_Run=true;
gettimeofday(&m_tpstart,NULL);
}
++m_CountPerSec;
//printf("trueMax[%d]\n",m_TrueMaxCount);
if(m_CountPerSec<m_TrueMaxCount)
{
//printf("%d\n",m_CountPerSec);
return 0;
}
int ret=0;
gettimeofday(&m_tpend,NULL);
int timeuse=1000000*(m_tpend.tv_sec-m_tpstart.tv_sec)+m_tpend.tv_usec-m_tpstart.tv_usec;//��
if(timeuse<=1000000 )
{
if(m_CountPerSec>=m_MaxCount)
{
m_Speed=m_CountPerSec;
//��̬����
m_TrueMaxCount=m_Speed;
usleep(1000000-timeuse);
gettimeofday(&m_tpstart,NULL);
m_CountPerSec=0;
ret = 1;
}
ret = 2;
}
else
{
m_Speed = m_CountPerSec*1000000/timeuse;
//��̬����
m_TrueMaxCount=m_Speed;
gettimeofday(&m_tpstart,NULL);
m_CountPerSec=0;
ret = 3;
}
return ret;
}/*}}}*/
/**
* @brief ��ȡ��ǰ�ٶ�
*
* @return �ٶ�
*/
int Speed()
{/*{{{*/
return m_Speed;
}/*}}}*/
/**
* @brief �����������
*/
void Clear()
{/*{{{*/
m_MaxCount=0;
m_TrueMaxCount=0;
m_CountPerSec=0;
m_Speed=0;
m_Run=false;
}/*}}}*/
private:
struct timeval m_tpstart,m_tpend;
//���õ�����ٶ�
int m_MaxCount;
//ͨ����̬�����õ�����ʵ��������ٶ�
int m_TrueMaxCount;
//������
int m_CountPerSec;
//��ǰ�ٶ�
int m_Speed;
bool m_Run;
};
#endif
/*
#include <iostream>
#include "timelimit.h"
using namespace std;
int main()
{
CTimeLimit timelimit;
timelimit.Init(10);
while(1)
{
timelimit.DetectAndLimit();
printf("%d\n",timelimit.Speed());
}
}
*/
记这个用于限速的函数为 DetectAndLimit
DetectAndLimit 中有三部分,第一部分判断函数是否初始化,没有初始化则使用 sys/time.h 中的 gettimeofday 获得一个系统时间;一部分统计自己被调用的次数,这个调用次数大于某一值时才检测延迟,之后清零,实现“检测程序速度”的时间间隔;最后一部分是检测延迟。
限速主体逻辑:
获得一个系统时间,与上一次获得的系统时间相减,得到一个时间间隔,如果这个时间间隔小于设定的值,那么就 usleep 这个时间间隔和设定时间之间的差,起到了限速的作用
调整理想值主体逻辑:
进入“检测程序速度”的逻辑之后,获得“检测程序速度的间隔所占的时间”,与单位时间相比:
如果“检测程序速度的间隔所占的时间”小于单位时间,继续判断如果“检测程序速度的间隔所占的函数调用历史次数”大于“给定的检测延迟的间隔所占的函数调用次数的理想值”,说明程序执行过快,等待一段时间,并设置“检测程序速度的间隔所占的函数调用理想次数”为该次“检测程序速度的间隔所占的函数调用历史次数”;否则说明程序执行的速度限度之下,直接返回;
如果“检测程序速度的间隔所占的时间”大于单位时间,不判断速度,缩小“检测程序速度的间隔所占的函数调用理想次数”,基于速度稳定的假设,下一次就应该使“检测程序速度的间隔所占的时间”等于单位时间,到那个时候再判断速度
(他应该是从来没有想过要用除法计算程序速度,而是单纯通过分子分母的大小判断整个分数的大小,所以才这么耦合)
参考:http://www.vimer.cn/2009/12/21/xian-su-lei-c-ban/
标签:逻辑,检测,间隔,限速,函数调用,次数,速度,延迟 来源: https://blog.csdn.net/PriceCheap/article/details/122756026