其他分享
首页 > 其他分享> > [C] 延迟限速逻辑

[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