当前位置: 首页 > 编程日记 > 正文

TCP拥塞控制算法内核实现剖析(二)

内核版本:2.6.37

主要源文件:linux-2.6.37/ net/ ipv4/ tcp_bic.c

本文主要分析BIC算法实现

======================================================================================================

1. 相关结构体和参数

/* BIC TCP Parameters */struct bictcp {u32 cnt ; /* increase cwnd by 1 after ACKs */u32 last_max_cwnd ; /* last maximum snd_cwnd */u32 loss_cwnd ; /* congestion window at last loss */u32 last_cwnd ; /* the last snd_cwnd */u32 last_time ; /* time when updated last_cwnd */u32 epoch_start ; /* beginning of an epoch */
#define ACK_RATIO_SHIFT 4u32 delayed_ack ; /* estimate the ratio of Packets/ACKs << 4 */
} ;

/* Scale factor beta calculation * max_cwnd = snd_cwnd * beta*/#define BICTCP_BETA_SCALE 1024 /* In binary search ,* go to point (max+min) / N*/#define BICTCP_B 4   /*并不是真正的二分*/

2. 全局变量

static int fast_convergence = 1 ; /* BIC能快速的达到一个平衡值,开关*/

static int max_increment = 16 ; /* 每次增加的MSS 不能超过这个值,防止增长太过剧烈*/

static int low_window = 14 ; /* lower bound on congestion window , for TCP friendliness */

static int beta = 819 ; /* = 819 / 1024(BICTCP_BETA_SCALE) ,beta for multiplicative increase 。?*/

static int initial_ssthresh ; /* 初始的阈值 */

static int smooth_part = 20 ; /* log(B/(B*Smin))/log(B/(B-1))+B, # of RTT from Wmax-B to Wmax 。?*/

/* initial_ssthresh的初始值被设置成2^31-1=2147483647 */

bictcp结构体保存在:

struct inet_connection_sock {...u32 icsk_ca_priv[16] ;
#define ICSK_CA_PRIV_SIZE (16*sizeof(u32))
}static inline void *inet_csk_ca( const struct sock *sk )
{return (void *)inet_csk(sk)->icsk_ca_priv ;
}

============================================================================================================

tcp_is_cwnd_limited的实现没弄明白

/* Slow start with delack produces 3 packets of burst , so that it is* safe "de facto". This will be default - same as the default reordering* threshold - but if reordering increases , we must be able to allow * cwnd to burst at least this much in order to not pull it back when * holes are filled.*/static __inline__ __u32 tcp_max_burst ( const struct tcp_sock *sk )
{return tp->reordering ;
}
/* u8 reordering ; Packets reordering metric */

/* RFC2681 Check whether we are limited by application or congestion * window . This is the inverse of cwnd check in tcp_tso_should_defer*/
/* 返回0,不需要增加cwnd ; 返回1,cwnd被限制,需要增加 */int tcp_is_cwnd_limited ( const struct sock *sk , u32 in_flight )
{const struct tcp_sock *tp = tcp_sk(sk) ;u32 left ;if( in_flight >= tp->snd_cwnd ) /* 不是规定in_flight < snd_cwnd ? */return 1 ;left = tp->snd_cwnd - in_flight ;if( sk_can_gso(sk) && left * sysctl_tcp_tso_win_divisor < tp->snd_cwnd &&left * tp->mss_cache < sk->sk_gso_max_size )return 1 ;return left <= tcp_max_busrt( tp ) ;
}

=============================================================================================================

3. bictcp拥塞避免

static void bictcp_cong_avoid ( struct sock *sk , u32 ack , u32 in_flight )
{struct tcp_sock *tp = tcp_sk(sk) ;struct bictcp *ca = inet_csk_ca(sk) ;/* 如果发送拥塞窗口不被限制,不能再增加,则返回 */if( !tcp_is_cwnd_limited(sk , in_flight))return ;if( tp->snd_cwnd < tp->snd_ssthresh )tcp_slow_start( tp ) ;else {bictcp_update(ca , tp->snd_cwnd ) ;tcp_cong_avoid_ai( tp , ca->cnt ) ;}
}

从以上函数可以看出,BIC的慢启动和reno相同。在拥塞避免阶段,当snd_cwnd <= low_window ,两者也采用相同方法。

只有当snd_cwnd > low_window时,BIC才开始显示出它的特性。

在include/ net / tcp.h中,

/* TCP timestamps are only 32-bits */

#define tcp_time_stamps ((__u32)(jiffies))

 4. bictcp结构体的更新(BIC算法关键)

/** Compute congestion window to use.*/
static inline void bictcp_update( struct bictcp *ca , u32 cwnd )
{/* 31.25ms以内不更新ca!!!*/if ( ca->last_cwnd == cwnd &&(s32) ( tcp_time_stamp - ca->last_time) <= HZ / 32 )return ;ca->last_cwnd = cwnd ;ca->last_time = tcp_time_stamp ;if ( ca->epoch_start == 0 ) /* recording the beginning of an epoch */ca->epoch_start = tcp_time_stamp ;/* start off normal */if( cwnd <= low_window ) {  /*为了保持友好性*/ca->cnt = cwnd ;  /*这样14个以内的ack,可使snd_cwnd++ */return ;}/* binary increase */if ( cwnd < ca->last_max_cwnd ) {  /*上次掉包前一个snd_cwnd */__u32 dist = (ca->last_max_cwnd - cwnd) / BICTCP_B ; /* 四分之一 */if ( dist > max_increment ) /* linear increase *//*dist > 16,处于线性增长阶段,每收到16个ACK,会使snd_cwnd++ */ca->cnt = cwnd / max_increment ;else if ( dist <= 1U ) /* binary search increase *//* dist <=1 , ca->cnt=5*cwnd,会造成snd_cwnd增长极其缓慢,即处于稳定阶段 */ca->cnt = (cwnd * smooth_part ) / BICTCP_B ; else /* binary search increase *//* 1 < dist <= 16 ,每收到dist个ACK,会使snd_cwnd++,故增长很快 */ca->cnt = cwnd / dist ; } else { /* 进入max_probing阶段 *//* cwnd < ca->last_max_cwnd + 4 */if ( cwnd < ca->last_max_cwnd + BICTCP_B ) /* ca->cnt = 5*cwnd ; slow start */ca->cnt = (cwnd * smooth_part ) / BICTCP_B ; else if ( cwnd < ca->last_max_cwnd + max_increment * ( BICTCP_B - 1))/* 增长率从5/(3*cwnd)~47/(3*cwnd),snd_cwnd的增长加快*/ca->cnt = (cwnd * (BICTCP_B - 1)) / (cwnd - ca->last_max_cwnd) ;else ca->cnt = cwnd / max_increment ;/* 增长率为16/cwnd ,更快 */}/* if in slow start or link utilization is very low */if ( ca->loss_cwnd == 0 ) {  /* 没有发生过丢包,所以snd_cwnd增长应该快点*/if ( ca->cnt > 20 )/* increase cwnd 5% per RTT */ca->cnt = 20 ;}/* 相当于乘与delayed_ack的百分比,delayed得越严重,则snd_cwnd应该增加越快*//* 这样有无delayed对snd_cwnd的影响不大*/ca->cnt = (ca->cnt << ACK_RATIO_SHIFT) / ca->delayed_ack ;/* ca->cnt cannot be zero */if ( ca->cnt == 0)ca->cnt = 1 ;

}

5. 小结:

从以上函数可以看出,和reno相比,BIC在拥塞避免阶段snd_cwnd增长极快。

当ca->last_max_cwnd - snd_cwnd >= 4 时,snd_cwnd最快的增长率为 1/16 。

而当ca->last_max_cwnd - snd_cwnd <4 时,增长率非常低,可以使当前的snd_cwnd维持很长一段时间,

即以最合适的snd_cwnd发送数据。

这两点使BIC在高带宽、长时延的环境下能达到较高的吞吐量。

1. 搜索阶段

(1) cwnd < last_max_cwnd - 64, 则cnt = cwnd / 16

(2) last_max_cwnd - 64 <= cwnd < last_max_cwnd -4 ,则cnt = cwnd / dist

(3) last_max_cwnd - 4 <= cwnd < last_max_cwnd ,则cnt = 5*cwnd

总体来说,snd_cwnd增长先快后慢,趋于稳定。

2. max probing阶段

(1) last_max_cwnd <= cwnd < last_max_cwnd + 4,则cnt = 5*cwnd

(2) last_max_cwnd + 4 <= cwnd < last_max_cwnd + 48 ,则cnt = 3*cwnd / (cwnd - last_max_cwnd)

(3) cwnd >= last_max_cwnd + 48 ,则cnt = cwnd / 16

总体来说,snd_cwnd的增长先慢后快,越来越快。

=======================================================================================================

来看一下初始化和重置

static inline void bictcp_reset( struct bictcp *ca )
{ca->cnt = 0 ;ca->last_max_cwnd = 0 ;ca->loss_cwnd = 0 ;ca->last_cwnd = 0 ;ca->last_time = 0 ;ca->epoch_start = 0 ;ca->delayed_ack = 2 << ACK_RATIO_SHIFT ; // 默认50%的delayed包
}

bictcp_reset在两种情况下被调用:初始化时(bictcp_init )、进入拥塞处理时(bictcp_state 状态为TCP_CA_Loss)。

static void bictcp_init( struct sock *sk )
{bictcp_reset( inet_csk_ca( sk) ) ;/* 加载模块时设置了。否则,其值 = 2^31 - 1 */if ( initial_ssthresh ) tcp_sk(sk)->snd_ssthesh = initial_ssthresh ;
}

=============================================================================================================

慢启动阈值调整

我们知道,对一个拥塞控制算法而言,有两个函数必不可少,除了上面分析过的bictcp_cong_avoid(拥塞避免),还有

bictcp_recalc_ssthresh(慢启动阈值重新计算)。RENO只是简单的把发生拥塞时的窗口除以2,而BIC则增加了一些东西。

/** behave like Reno until low_window is reached , * then increase congestion window slowly*/
static u32 bictcp_recalc_ssthresh( struct sock *sk )
{const struct tcp_sock *tp = tcp_sk(sk) ;struct bictcp *ca = inet_csk_ca(sk) ;ca->epoch_start = 0 ; /* end of epoch,平静的日子结束了 *//* Wmax and fast convergence* fast? 好像是更安全点吧。丢包点比上次低,说明恶化,则主动降低。* 丢包点比上次高,则说明更好,当然采用更大的。*/if ( tp->snd_cwnd < ca->last_max_cwnd && fast_convergence )/* 就是last_max_cwnd = 0.9 * snd_cwnd */ca->last_max_cwnd = (tp->snd_cwnd * (BICTCP_BETA_SCALE + beta ))/ ( 2 * BICTCP_BETA_SCALE ) ; esleca->last_max_cwnd = tp->snd_cwnd ;ca->loss_cwnd = tp->snd_cwnd ;/* snd_cwnd<=14时,同reno,保持友好性 */if ( tp->snd_cwnd <= low_window )return max( tp->snd_cwnd >> 1U , 2U ) ;esle/* 就是snd_ssthresh=0.8*snd_cwnd ,很大的一个数,能充分利用带宽 */return max( tp->snd_cwnd * beta ) / BICTCP_BETA_SCALE , 2U ) ;
}

bictcp_recalc_ssthresh做了两件事:重赋值last_max_cwnd、返回新的慢启动阈值。

特别值得注意的是,snd_ssthresh = 0.8 * snd_cwnd 。这个可比RENO的snd_ssthresh = 0.5 * snd_cwnd 大了很多。

所以说BIC能够更有效的利用大带宽。

=======================================================================================================
计算delayed packets ratio

/* Track delayed acknowledgement ratio using sliding window* ratio = (15*ratio + sample) / 16* sample是此时的cnt,而本来的ratio = delayed_ack / 16 * 按如下函数计算后,现在的ratio = (15*ratio) /16 + cnt /16* cnt = cnt - 原来的ratio*/static void bictcp_acked( struct sock *sk , u32 cnt , s32 rtt )
{const struct inet_connection_sock *icsk = inet_csk(sk) ;if ( icsk->icsk_ca_state == TCP_CA_Open ) {struct bictcp *ca = inet_csk_ca(sk) ;/* 作者似乎很注重delayed包对snd_cwnd的影响,要尽量削弱 */cnt -= ca->delayed_ack >> ACK_RATIO_SHIFT ; ca->delayed_ack += cnt ;}
}

在struct inet_connection_sock中,有__u8 icsk_ca_state,表示拥塞控制的状态。

在tcp.h中,

enum tcp_ca_state {TCP_CA_Open = 0,
#define TCPF_CA_Open	(1<<TCP_CA_Open)TCP_CA_Disorder = 1,
#define TCPF_CA_Disorder (1<<TCP_CA_Disorder)TCP_CA_CWR = 2,
#define TCPF_CA_CWR	(1<<TCP_CA_CWR)TCP_CA_Recovery = 3,
#define TCPF_CA_Recovery (1<<TCP_CA_Recovery)TCP_CA_Loss = 4
#define TCPF_CA_Loss	(1<<TCP_CA_Loss)
};

============================================================================================================

static u32 bictcp_undo_cwnd( struct sock *sk )
{const struct tcp_sock *tp = tcp_sk(sk) ;const struct bictcp *ca = inet_csk_ca(sk) ;return max( tp->snd_cwnd , ca->last_max_cwnd ) ;
}


此函数在退出拥塞处理时调用,而下面的bictcp_state则是在进入拥塞处理时调用。

static void bictcp_state( struct sock *sk , u8 new_state )
{if ( new_state == TCP_CA_Loss )bictcp_reset( inet_csk_ca(sk) ) ;
}

============================================================================================================

bictcp算法结构体

static struct tcp_congestion_ops bictcp = {. init = bictcp_init ,. ssthresh = bictcp_recalc_ssthresh ,. cong_avoid = bictcp_cong_avoid ,. set_state = bictcp_state ,. undo_cwnd = bictcp_undo_cwnd ,. pkts_acked = bictcp_acked ,. owner = THIS_MODULE ,. name = "bic" ,
} ;


bictcp注册函数

static int __init bictcp_register(void)
{/* bic算法的参数不能太多,多于16个u32 */BUILD_BUG_ON( sizeof( struct bictcp) ) > ICSK_CA_PRIV_SIZE ) ;return tcp_register_congestion_control( &bictcp ) ;
}


 
 OK,关于BIC的代码分析告一段落,接下来看看相关函数是在什么样的情况下,以什么顺序来调用的。

======================================================================================================

BIC函数的调用时机

1. 连接每收到一个ack,则调用tcp_ack

2. tcp_ack会调用bictcp_acked,用来更新cnt和delayed_ack(用来消除delay包的影响)

3. tcp_ack会调用bictcp_cong_avoid,这是分两种情况:

(1)snd_cwnd小于慢启动阈值,处于慢启动阶段,则调用tcp_slow_start

(2)snd_cwnd大于慢启动阈值,处于拥塞避免阶段,则调用bictcp_update来更新bictcp,再调用tcp_cong_avoid_ai

4. tcp_ack中如果检测到丢包,进入拥塞处理阶段,则调用bictcp_recalc_ssthresh来更新慢启动阈值。

5. tcp_ack中完成丢包重传后,退出拥塞处理阶段,则调用bictcp_undo_cwnd来更新snd_cwnd。

快速重传:tcp_ack中的丢包检测,即检测到连续3个重复ACK。

快速恢复:bictcp_undo_cwnd,直接把snd_cwnd更新为max(snd_cwnd,last_max_cwnd),和掉包前相差不大。

更具体的可以看看tcp_ack(net/ ipv4/ tcp_input.c)。

转载于:https://www.cnblogs.com/aiwz/archive/2011/12/14/6333403.html

相关文章:

关于IOS中的self关键字

在C#、Java中都有一个关键字this用于表示当前对象&#xff0c;其实在ObjC中也有一个类似的关键字self&#xff0c;只是self不仅可以表示当前对象还可以表示类本身&#xff0c;也就是说它既可以用在静态方法中又可以用在动态方法中。-(void)setName:(NSString *)name andAge:(in…

中值定理符号怎么读_微分、微分中值定理、泰勒公式

问对问题&#xff0c;找对方法&#xff0c;做对的事~ 黑莓 2020/10/09 温习001-031逻辑、集合、空间 线性代数00线性代数研究什么内容&#xff1f;-上海交大032-047行列式的定义、性质与计算10/03048-078矩阵的定义、运算10/03079-117可逆矩阵、初等变换与秩10/04…

Java高级特性增强-多线程

请戳GitHub原文: https://github.com/wangzhiwub... 大数据成神之路系列&#xff1a; 请戳GitHub原文: https://github.com/wangzhiwub... Java高级特性增强-集合 Java高级特性增强-多线程 Java高级特性增强-Synchronized Java高级特性增强-volatile Java高级特性增强-并发集合…

微软企业库4.1学习笔记(八)创建对象 续集2

3.3通过配置指定和Unity的整合 另外一种方法是在配置源中指定配置的需要&#xff0c;你可以指定下面的一条或者多条&#xff1a; 你可以在Unity配置中指定想要的BlockExtensions  你可以在Unity配置中的type配置节指定如何创建企业库对象&#xff0c;指定类型映射的关系&…

Kali Linux python 安装pip

安装pip&#xff1a;apt-get install python-setuptoolseasy_install pippip install xxxx转载于:https://www.cnblogs.com/arhatlohan/p/4737828.html

3dmax图像采样器抗锯齿_内幕揭秘!同样的场景同一张图,用3DMAX网渲平台进行二次渲染时间竟然相差3个小时之多!...

一个分辨率:4000*2000的室内客餐厅&#xff0c;3dmax版本是2014版本&#xff0c;渲染器版本为vray3.63&#xff0c;机器&#xff1a;阿里云1台服务器&#xff0c;这个同样的场景同样的参数同一张图&#xff0c;用3dmax网渲平台进行二次渲染发现时间相差了将近3个小时之多&#…

2015/8/18

一、git, switch to找不到师傅新创的branch 解决方法&#xff1a;切到git视图去pull&#xff0c;然后切回java视图&#xff0c;再Team->switch to&#xff0c;就能找到了 二、在师傅的环境中能successful&#xff0c;在我的环境中却是failed 解决方法&#xff1a;eclipse-&g…

Javascript - prototype、__proto__、constructor

最近看了很多文章&#xff0c;想要更通透的搞懂JS中的prototype、__proto__与constructor属性&#xff0c;从各个博主的文章里摘取了我认为可以有助于理解的一些内容&#xff0c;希望自己能够掌握好这一重要知识点的同时也帮助到大家&#xff0c;具体内容请见下文。 &#xff0…

DOS下读取4GB内存

好文章我收集下起来 CPU上电后&#xff0c;从ROM 中的BIOS开始运行。 BIOS是处在内存的最顶端64KB&#xff08;FFFF0000H&#xff09;&#xff0c;还是1MB之下的64KB&#xff08;F0000H&#xff09;处呢&#xff1f;事实上&#xff0c;BIOS在这两个地方都同时出现。 在保护模式…

7纳米duv和euv_要超车台积电 三星宣布采用EUV技术7纳米制程完成验证

在晶圆代工市场&#xff0c;台积电与三星的竞争始终是大家关心的戏码。三星虽然有高通等VIP客户&#xff0c;但在7纳米制程节点&#xff0c;高通预计会转投台积电&#xff0c;三星要想受更多客户的青睐&#xff0c;只能从制程技术着手了。这也是三星跳过非EUV技术的7纳米制程&a…

HDU 1711 Number Sequence(KMP算法)

题目链接&#xff1a;http://acm.hdu.edu.cn/showproblem.php?pid1711 Number Sequence Time Limit: 10000/5000 MS (Java/Others) Memory Limit: 32768/32768 K (Java/Others) Total Submission(s): 15548 Accepted Submission(s): 6836Problem DescriptionGiven two s…

分享45款高质量的免费(X)HTML/CSS模板

当你需要在短时间内设计出一个网站的时候&#xff0c;网站模板就非常有用了。这也就是为什么这些设计模板已成为设计领域的最新趋势的原因。在这篇文章中&#xff0c;收集了各式各样的网站模板&#xff0c;您可以免费下载使用&#xff0c;希望这些设计模板不仅带给您灵感&#…

运维开发笔记整理-前后端分离

运维开发笔记整理-前后端分离 作者&#xff1a;尹正杰 版权声明&#xff1a;原创作品&#xff0c;谢绝转载&#xff01;否则将追究法律责任。 一.为什么要进行前后端分离 1>.pc, app, pad多端适应 2>.SPA开发式的流行&#xff08;单页Web应用&#xff08;single page we…

初识mysql数据字段属性_MySQL数据库~~~~初识、基础数据类型

一 数据库初识1.1 什么是数据库数据库(DataBase,简称DB),简而言之可视为电子化的文件柜----存储电子文件的处所,用户可以对文件中的数据运行新增,截取,更新,删除等操作. 所谓数据库是以一定方式储存在一起,能予多个用户 共享,具有尽可能小的冗余度,与应用程序彼此独立的数据集合…

WinForm导出文件,你懂的……

好久没有写文章了&#xff0c;下面把自己最近程序中用到的一个小小的导出文件的方法给在家分享一下&#xff0c;欢迎大家来排砖&#xff0c;谢谢~不说废话了&#xff0c;直接上代码&#xff1a; 1 using System; 2 using System.Collections.Generic; 3 using System.Linq; …

PL/SQL第五章 Order by排序

1 -- 排序2 -- 1、列明排序3 -- 2、别名排序4 -- 3、列位置排序&#xff08;当使用union,union all,intersect,minus集合操作&#xff0c;列明不同&#xff0c;但希望排序&#xff09;5 SELECT deptno,dname FROM dept UNION6 SELECT empno,ename FROM emp7 ORDER BY 1 DESC;8 …

想转行学python过来人提醒大家几点

因为目前python非常火&#xff0c;应用也非常广泛&#xff0c;是目前最火的行业之一&#xff0c;竞争很大&#xff0c;工资很高&#xff0c;未来发展也极好。 首先告诉你&#xff0c;零基础学习python难度还是有的&#xff0c;python的专业程度本身就不简单&#xff0c;学习这事…

mysql答题表设计_PHP+MYSQL问答系统中的提问和回答的表怎么设计

展开全部PHPMYSQL 的问答系32313133353236313431303231363533e78988e69d8331333337396236统的设计与实现&#xff0c;问答系统简而言之 就是一个网上交流系统&#xff0c;针对学校这个特定环境&#xff0c;以学生和老师为主体&#xff0c;以实验室信息交流为话题而建立起的一个…

Android实时获取音量(单位:分贝)

基础知识 度量声音强度&#xff0c;大家最熟悉的单位就是分贝&#xff08;decibel&#xff0c;缩写为dB&#xff09;。这是一个无纲量的相对单位&#xff0c;计算公式如下&#xff1a; 分子是测量值的声压&#xff0c;分母是参考值的声压&#xff08;20微帕&#xff0c;人类所能…

排序算法 - 堆排序

堆排序是指利用堆这种数据结构所设计的一种排序算法。 类型&#xff1a;选择排序时间复杂度&#xff08;最坏&#xff09;&#xff1a;O(nlogn)时间复杂度&#xff08;最好&#xff09;&#xff1a;O(nlogn)时间复杂度&#xff08;平均&#xff09;&#xff1a;O(nlogn)空间复杂…

textContent与innerText的不同(转发)

textContent与innerText的不同 IE下有个innerText属性&#xff0c;FF下有个textContent属性。很多以前给IE写脚本的&#xff0c;在FF下找不到innerText属性&#xff0c;于是网上搜到的建议是用textContent来替代。反之给FF写脚本的也一样。 但是实际上&#xff0c;这里有个误解…

mysql插入性能_mysql 数据量大时插入和查询性能

现在mysql中有数据33.8w的数据&#xff0c;然后做查询和更新或插入操作&#xff0c;速度很慢&#xff0c;基本100条数据就要1.68s。好慢啊&#xff0c;我要测试一下&#xff0c;到底慢在哪&#xff1f;能不能提高点速度&#xff1f;参考一篇博文&#xff1a;http://blog.csdn.n…

Ext JS 4 笔记1

ExtJS4 引入了现在灰常流行的前端MVC。这在原本的3.3.1里面是没有的。原先项目里为了实现相对的MVC&#xff0c;自己写了一个controller和model &#xff0c;收集并且保持JS端的数据。所以呢&#xff0c;这时候的文档结构就完全不一样了。原本的结构更像是传统 C# winform &…

activemq 消息阻塞优化和消息确认机制优化

一、消息阻塞优化 1.activemq消费者在从待消费队列中获取消息是会先进行预读取&#xff0c;默认是1000条&#xff08;prefetch1000&#xff09;。这样很容易造成消息积压。 2.可以通过设置prefetch的默认值来调整预读取条数&#xff0c;java代码如下 //设置预读取为1ActiveMQPr…

iOS-查询数据库--指定数据表中的当前数据行的总数量

很多时候&#xff0c;我们在查询一个表的时候&#xff0c;不想得到里面的记录内容&#xff0c;只是想简单的得到符合查询条件的记录条数。 FMDB中有一个很简单的方法就可以实现&#xff0c;见下面的代码实例&#xff1a; #import "FMdatabase.h" (int)numberOfCurre…

mysql 判断日期是否在某范围内_判断时间是否在某个区间内

private bool IsInTimeInterval(DateTime time, DateTime startTime, DateTime endTime) {//判断时间段开始时间是否小于时间段结束时间,如果不是就交换 if (startTime > endTime) {DateTime tempTime = startTime; startTime = endTime; endTime = tempTime; } //获取以公…

数据库索引-基本知识

为什么80%的码农都做不了架构师&#xff1f;>>> 数据库索引--基本知识 有许多因素会影响数据库性能。最明显的是数据量&#xff1a;您拥有的数据越多&#xff0c;数据库的速度就越慢。虽然有很多方法可以解决性能问题&#xff0c;但主要的解决方案是正确索引数据库…

Microsoft Enterprise Library 5.0 系列(八) Unity Dependency Injection and Interception

依赖注入容器Unity: Unity的构造类似于Castle中的IOC&#xff08;控制反转 或者叫依赖注入&#xff09;容器,我们使用抽象接口来隔离使用者和具体实现之间的依赖关系&#xff0c;但是不管再怎么抽象&#xff0c;最终还是要创建具体实现类的实例&#xff0c;这种创建具体实现类的…

pycharm 使用小结

1.pycharm 自动换行,显示行号,缩进向导 在代码右侧右键 2.自动注释/取消注释 ctrl /转载于:https://www.cnblogs.com/xuesu/p/4755086.html

golang socket读写同时_epoll在Golang的应用

使用Golang可以轻松地为每一个TCP连接创建一个协程去服务而不用担心性能问题&#xff0c;这是因为Go内部使用goroutine结合IO多路复用实现了一个“异步”的IO模型&#xff0c;这使得开发者不用过多的关注底层&#xff0c;而只需要按照需求编写上层业务逻辑。这种异步的IO是如何…