ICode9

精准搜索请尝试: 精确搜索
首页 > 其他分享> 文章详细

[C] 延迟限速逻辑

2022-01-31 13:04:15  阅读:167  来源: 互联网

标签:逻辑 检测 间隔 限速 函数调用 次数 速度 延迟


把一个函数放到一个循环中,这个函数被调用的频率在一定程度上反映了程序的速度。


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

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有