当前位置: 首页 > news >正文

c程序杂谈系列(职责链模式与if_else)

从处理器的角度来说,条件分支会导致指令流水线的中断,所以控制语句需要严格保存状态,因为处理器是很难直接进行逻辑判断的,有可能它会执行一段时间,发现出错后再返回,也有可能通过延时等手段完成控制流的正确性。所以笔者在想,使用过多的if _else,除了可读性差,是否还会对执行效率造成影响呢?

于是笔者决定采用职责链重构if控制语句,笔者猜想,如果采用设计模式既可以避免if分支,提高执行效率,同时可以让程序具备解耦合性和可维护性,是否是一种更优解呢?

为了验证笔者的猜想,更好的优化c语言程序,笔者使用职责链模式对一段if_else程序进行了重构。

程序的性能标准是执行时间,计算程序时间的程序来源于:C语言 计算程序运行时间(精确到毫秒/微秒)_c语言计算运行时间-CSDN博客

以下是笔者本人用c编写的责任链设计模式:

#include<stdio.h>
#include<stdlib.h>
#include<memory.h>
#include<string.h>
#include <windows.h>typedef int (*Handler)(int);typedef struct task_node
{Handler handler;struct task_node* next;
}taskN;int task1(int a) {if (a == 1) {//printf("a == 1"); printf会耗费大量时间,为了不影响测试,所以只留下判断语句return 0;}return -1;
}int task2(int a) {if (a == 2) {return 0;}return -1;
}int task3(int a) {if (a == 3) {return 0;}return -1;
}int task4(int a) {if (a == 4) {return 0;}return -1;
}int task5(int a) {if (a == 5) {return 0;}return -1;
}int task6(int a) {if (a == 6) {return 0;}return -1;
}int task7(int a) {if (a == 7) {return 0;}return -1;
}int task8(int a) {if (a == 8) {return 0;}return -1;
}int task9(int a) {if (a == 9) {return 0;}return -1;
}int task10(int a) {if (a == 10) {return 0;}return -1;
}int task11(int a) {if (a == 11) {return 0;}return -1;
}int task12(int a) {if (a == 12) {return 0;}return -1;
}taskN* initi() {taskN* tas1 = malloc(sizeof(taskN));taskN* tas2 = malloc(sizeof(taskN));taskN* tas3 = malloc(sizeof(taskN));taskN* tas4 = malloc(sizeof(taskN));taskN* tas5 = malloc(sizeof(taskN));taskN* tas6 = malloc(sizeof(taskN));taskN* tas7 = malloc(sizeof(taskN));taskN* tas8 = malloc(sizeof(taskN));taskN* tas9 = malloc(sizeof(taskN));taskN* tas10 = malloc(sizeof(taskN));taskN* tas11= malloc(sizeof(taskN));taskN* tas12= malloc(sizeof(taskN));tas1->handler = task1;tas2->handler = task2;tas3->handler = task3;tas4->handler = task4;tas5->handler = task5;tas6->handler = task6;tas7->handler = task7;tas8->handler = task8;tas9->handler = task9;tas10->handler = task10;tas11->handler = task11;tas12->handler = task12;tas1->next = tas2;tas2->next = tas3;tas3->next = tas4;tas4->next = tas5;tas5->next = tas6;tas6->next = tas7;tas7->next = tas8;tas8->next = tas9;tas9->next = tas10;tas10->next = tas11;tas11->next = tas12;return tas1;}void process(taskN* bol, int a) {int i = bol->handler(a);while (i != 0){i = bol->handler(a);bol = bol->next;}
}void main() {double run_time;LARGE_INTEGER time_start;	//开始时间LARGE_INTEGER time_over;	//结束时间double dqFreq;		//计时器频率LARGE_INTEGER f;	//计时器频率QueryPerformanceFrequency(&f);dqFreq = (double)f.QuadPart;QueryPerformanceCounter(&time_start);taskN* bol = initi();int a = 12;for (int i = 0; i <= 50000000; i++){/*if (a == 1) {}else if (a == 2) {}else if (a == 3) {}else if (a == 4) {}else if (a == 5) {}else if (a == 6) {}else if (a == 7) {}else if (a == 8) {}else if (a == 9) {}else if (a == 10) {}else if (a == 11) {}else if (a == 12) {}else {}*//*process(bol, a);*/switch (a) {case 1:break;case 2:break;case 3:break;case 4:break;case 5:break;case 6:break;case 7:break;case 8:break;case 9:break;case 10:break;case 11:break;case 12:break;default:break;}}QueryPerformanceCounter(&time_over);	//计时结束run_time = 1000000 * (time_over.QuadPart - time_start.QuadPart) / dqFreq;//乘以1000000把单位由秒化为微秒,精度为1000 000/(cpu主频)微秒printf("\nrun_time:%fus\n", run_time);/*为了偷懒,程序就懒得free了*/}

使用if_else时:

a=1,第一个循环执行:

a=12,最后一个循环执行:

两者时间基本没区别,在循环语句中

笔者还测试了只有if( a== 1)这一个判断语句下的性能:

可以看出基本没什么区别。

使用case时:

a=12时如下,与a=1时的结果几乎没有区别:

switch语句除了比较简洁一点,执行速度完全没法比。

 使用责任链时:

任务优先级在责任链上过高(a=1):

 任务优先级在责任链过低(a=12):

可以看出,职责链的速度非常慢,特别是任务优先级低时,执行速度几乎是if_else的150倍。

综上得出,if_else的执行速度是最快的,如果判断的时间复杂度过大,而且判断语句的数量较少,使用if_else,性能可能会更好。

但是,上述的前提是建立在判断语句的数量较少的情况下。

现在让我们考虑这样一种情况:不是判断a从1到12,而是从a到10000呢?程序等价于下图:

再附加一个条件,大多数情况下,a的值都是1。

虽然if_else的耗时比较短,但是在大量的循环下,耗时也不容小觑。因为a大多数情况是1,其他的判断分支只有小概率发生,此时我们使用责任链就可以完美跳过这些语句的判断:

(程序用for循环表示中间的分支,写得不准确,理解意思就好)

当然,读者可能认为if else if在这里也可以跳过中间的语句,也能实现优先级,但是如果改成这样呢:

这种情况下,if else if只能执行其中一个,显然不行,使用大量的if,就变成了上面的情况,我们不得不将原先的代码大量删除并重写,这十分让人难受。这样一对比,对于部分实现的if分支,使用责任链的优点有什么呢?如下图:

在责任链任务里进行改动,可以选择责任链终止的位置,跳过后面的任务,当然,通过goto等跳转指令也是可以实现的,但是if语句很难做到这样灵活,对于复杂的业务场景,很难在原先的基础上进行拓展,责任链的解耦合性和可拓展性是非常好的优点。

考虑复杂的业务场景,责任链明显优于传统的if_else。

尽管如此,if_else还是十分友好的,特别是在mcu等产品的开发中,使用设计模式的资源花费简直是奢求,毕竟设计模式是针对高级语言的,大多数情况下if_else往往是最优解。不过,笔者认为大量使用if_else的前提是项目不需要长期维护,一般情况下还是要多使用设计模式,例如在linux内核中就有源码使用了责任链模式,这是从性能,解耦合性和可读性等多方面考虑,值得开发者学习。如果是小型项目,对维护没有要求,而且控制语句的数量较少,为了性能和简便性可以考虑直接使用if_else分支。但是如果大型项目中含有大量if分支,可以考虑使用设计模式重构。

相关文章:

c程序杂谈系列(职责链模式与if_else)

从处理器的角度来说&#xff0c;条件分支会导致指令流水线的中断&#xff0c;所以控制语句需要严格保存状态&#xff0c;因为处理器是很难直接进行逻辑判断的&#xff0c;有可能它会执行一段时间&#xff0c;发现出错后再返回&#xff0c;也有可能通过延时等手段完成控制流的正…...

前端开发技术之CSS(层叠样式表)

盒模型&#xff08;Box Model&#xff09; CSS盒模型描述了如何计算一个元素的总宽度和高度。 它包括以下几个部分&#xff1a; 1. 内容&#xff08;Content&#xff09;&#xff1a;元素的实际内容&#xff0c;比如文本或图片。 2. 内边距&#xff08;Padding&#xff09;&…...

go语言day20 使用gin框架获取参数 使用自定义的logger记录日志

Golang 操作 Logger、Zap Logger 日志_golang zap-CSDN博客 目录 一、 从控制器中获取参数的几种形式 1&#xff09; 页面请求url直接拼接参数。 2&#xff09; 页面请求提交form表单 3&#xff09; 页面请求发送json数据&#xff0c;使用上下文对象c的BindJSON()方法接…...

DHCP笔记

DHCP---动态主机配置协议 作用&#xff1a;为终端动态提供IP地址&#xff0c;子网掩码&#xff0c;网关&#xff0c;DNS网址等信息 具体流程 报文抓包 在DHCP服务器分配iP地址之间会进行广播发送arp报文&#xff0c;接收IP地址的设备也会发送&#xff0c;防止其他设备已经使用…...

TCP为什么需要四次挥手?

tcp为什么需要四次挥手&#xff1f; 答案有两个&#xff1a; 1.将发送fin包的权限交给被动断开发的应用层去处理&#xff0c;也就是让程序员处理 2.接第一个答案&#xff0c;应用层有了发送fin的权限&#xff0c;可以在发送fin前继续向对端发送消息 为了搞清楚这个问题&…...

MySQL 索引相关基本概念

文章目录 前言一. B Tree 索引1. 概念2. 聚集索引/聚簇索引3. 辅助索引/二级索引4. 回表5. 联合索引/复合索引6. 覆盖索引 二. 哈希索引三. 全文索引 前言 InnoDB存储引擎支持以下几种常见索引&#xff1a;BTree索引&#xff0c;哈希索引&#xff0c;全文索引 一. B Tree 索引…...

Neutralinojs教程项目实战初体验(踩坑指南),干翻 electron

Neutralinojs 项目实战初体验&#xff08;踩坑指南&#xff09;&#xff0c;干翻 electron Neutralinojs 官方文档 卧槽卧槽&#xff0c;&#xff01;这个年轻人居然用浏览器把电脑关机了_哔哩哔哩_bilibili正是在下 本教程搭建的是纯原生项目&#xff0c;没有和其它前端框架…...

【轻松拿捏】Java-List、Set、Map 之间的区别是什么?

List、Set、Map 之间的区别是什么&#xff1f; 一、List 二、Set 三、Map &#x1f388;边走、边悟&#x1f388;迟早会好 一、List 有序性&#xff1a;List 保持元素的插入顺序&#xff0c;即元素按添加的顺序存储和访问。允许重复&#xff1a;List 可以包含重复的元素。…...

用户史订单查询业务

文章目录 概要整体架构流程技术细节小结 概要 在电商、金融、物流等行业中&#xff0c;用户历史订单查询是一项常见的业务需求。这项功能允许用户查看他们过去的交易记录&#xff0c;包括但不限于购买的商品、服务详情、交易金额、支付状态、配送信息等。对于企业而言&#xf…...

第8节课:CSS布局与样式——掌握盒模型与定位的艺术

目录 盒模型&#xff1a;网页布局的基础盒模型的属性盒模型的示例 定位&#xff1a;控制元素位置定位的类型定位的示例 实践&#xff1a;使用CSS布局创建响应式网页结语 CSS布局是网页设计中的基石&#xff0c;它决定了网页元素的排列和分布。盒模型和定位是CSS布局中的两个核心…...

electron 主进程和渲染进程

最近在整理electron 相关的项目问题&#xff0c;对自己来说也是温故知新&#xff0c;也希望能对小伙伴们有所帮助&#xff0c;大家共同努力共同进步。加油&#xff01;&#xff01;&#xff01;&#xff01; 虽然最近一年前端大环境不好&#xff0c;但是大家还是要加油鸭&#…...

redis的高可用及性能管理和雪崩

redis的高可用 redis当中&#xff0c;高可用概念更宽泛一些。 除了正常服务以外&#xff0c;数据量的扩容&#xff0c;数据安全。 实现高可用的方式&#xff1a; 1、持久化 最简单的高可用方法&#xff0c;主要功能就是备份数据。 把内存当中的数据保存到硬盘当中。 2、主…...

php基础语法

文章目录 1. PHP(1) 安装php 2. 基础语法(1) 格式(2) 输出语法(3) 注释(4) 变量(无变量类型自动识别)(5) 输入获取(6) 定界符(7) 换行 3. 基本数据类型(1) 字符串(2) 整数(3). 浮点数(4). boolean类型(5). 数组(6). null值 4. 运算符(1) 算术运算符(2) 比较运算符(3) 逻辑运算符…...

js抓取短信验证码发送

油猴(Tampermonkey)是一个流行的浏览器扩展,它允许用户在浏览器中运行自定义的JavaScript脚本。下面是一个简单的示例脚本,用于收集网站上发送短信验证码的API请求,并以JSON格式存储这些信息。请注意,这个脚本需要根据实际网站的API请求进行调整,因为不同的网站可能有不…...

视频怎么加密?常见的四种视频加密方法和软件

视频加密是一种重要的技术手段&#xff0c;用于保护视频内容不被未经授权的用户获取、复制、修改或传播。在加密过程中&#xff0c;安企神软件作为一种专业的加密工具&#xff0c;可以发挥重要作用。 以下将详细介绍如何使用安企神软件对视频进行加密&#xff0c;并探讨视频加密…...

聚焦全局应用可用性的提升策略,详解GLSB是什么

伴随互联网的快速发展和全球化趋势的深入&#xff0c;企业对网络应用的需求日渐增长。为满足全球范围内用户大量的访问需求&#xff0c;同时解决容灾、用户就近访问以及全球应用交付等问题&#xff0c;GLSB&#xff08;全局负载均衡&#xff09;也因此应运而生。那么GLSB是什么…...

无水印下载视频2——基于tkinter完成头条视频的下载

在数字化时代的浪潮中&#xff0c;视频内容以其丰富性和便捷性&#xff0c;逐渐成为了我们获取信息和娱乐的重要途径。尤其是在短视频平台上&#xff0c;各种创意十足、内容精彩的视频层出不穷&#xff0c;更是吸引了数以亿计的用户。然而&#xff0c;随着视频内容的增加&#…...

Java学习Day17:基础篇7

继承 Java中的继承是面向对象编程中的一个核心概念&#xff0c;它允许我们定义一个类&#xff08;称为子类或派生类&#xff09;来继承另一个类&#xff08;称为父类或基类&#xff09;的属性和方法。继承提高了代码的复用性&#xff0c;使得我们不必从头开始编写所有的代码&a…...

Vue3 Pinia的创建与使用代替Vuex 全局数据共享 同步异步

介绍 提供跨组件和页面的共享状态能力&#xff0c;作为Vuex的替代品&#xff0c;专为Vue3设计的状态管理库。 Vuex&#xff1a;在Vuex中&#xff0c;更改状态必须通过Mutation或Action完成&#xff0c;手动触发更新。Pinia&#xff1a;Pinia的状态是响应式的&#xff0c;当状…...

手撕数据结构02--二分搜索(附源码)

一、理论基础 二分搜索&#xff0c;也称折半搜索、对数搜索&#xff0c;是一种在有序数组中查找某一特定元素的搜索算法。 二分搜索是一种高效的查找算法&#xff0c;适用于在已排序的数组中查找特定元素。它的基本思想是通过不断将搜索区间对半分割&#xff0c;从而快速缩小…...

Atlas800T A2上部署Qwen2.5-Omni-7B音频模型:从驱动安装到vllm-ascend服务启动的保姆级避坑记录

Atlas800T A2服务器部署Qwen2.5-Omni-7B音频模型全流程实战指南 在昇腾Atlas800T A2服务器上部署多模态大模型Qwen2.5-Omni-7B&#xff0c;对于需要处理音频转文字任务的开发者而言&#xff0c;既是技术挑战也是效率提升的关键一步。本文将带你从零开始&#xff0c;逐步完成从硬…...

电商智能客服:基于Qwen3-VL:30B的多模态问答系统实现

电商智能客服&#xff1a;基于Qwen3-VL:30B的多模态问答系统实现 1. 引言 电商客服每天面对海量咨询&#xff0c;从"这件衣服有没有M码"到"这个电器怎么安装"&#xff0c;问题五花八门。传统客服需要不停切换商品页面、说明书、物流信息&#xff0c;忙得…...

GLM-4.1V-9B-Base实际作品集:10张典型图片的多角度中文理解结果

GLM-4.1V-9B-Base实际作品集&#xff1a;10张典型图片的多角度中文理解结果 1. 模型能力概览 GLM-4.1V-9B-Base是智谱开源的视觉多模态理解模型&#xff0c;专为中文视觉理解任务设计。这个模型最令人印象深刻的地方在于&#xff0c;它能像人类一样"看"图片并回答各…...

【独家首发】CPython官方GIL移除路线图深度解读(附内部邮件泄露+性能基准测试数据),错过再等十年

第一章&#xff1a;Python无锁GIL环境下的并发模型演进全景Python长期以来受全局解释器锁&#xff08;GIL&#xff09;制约&#xff0c;导致多线程无法真正并行执行CPU密集型任务。近年来&#xff0c;随着CPython 3.12正式引入实验性无GIL构建选项&#xff08;通过--without-py…...

OpenClaw学习助手:用gemma-3-12b-it自动整理课程笔记与习题

OpenClaw学习助手&#xff1a;用gemma-3-12b-it自动整理课程笔记与习题 1. 为什么需要AI学习助手&#xff1f; 作为一名经常需要消化大量课程资料的技术从业者&#xff0c;我长期被三个问题困扰&#xff1a;PDF讲义信息碎片化难以形成体系、课堂重点难以快速提炼、错题整理耗…...

气动元器件选型(工业自动化场景实战指南)

1. 气动技术基础与工业自动化适配性 气动技术作为工业自动化领域的核心驱动方式之一&#xff0c;其本质是通过压缩空气实现能量传递。想象一下&#xff0c;就像我们用吸管吹动纸团一样简单直接——空压机将电动机的旋转动能转化为气压能&#xff0c;再通过各类阀门控制气流方向…...

Symfony Monolog Bundle终极指南:如何快速搭建专业日志系统

Symfony Monolog Bundle终极指南&#xff1a;如何快速搭建专业日志系统 【免费下载链接】monolog-bundle Symfony Monolog Bundle 项目地址: https://gitcode.com/gh_mirrors/mo/monolog-bundle Symfony Monolog Bundle是Symfony框架中一款强大的日志管理工具&#xff0…...

如何使用hello-uniapp性能监控工具实时掌握应用运行状态

如何使用hello-uniapp性能监控工具实时掌握应用运行状态 【免费下载链接】hello-uniapp uni-app框架演示示例 项目地址: https://gitcode.com/gh_mirrors/he/hello-uniapp hello-uniapp性能监控工具是uni-app框架演示示例中的核心功能模块&#xff0c;它提供了一套完整的…...

logback 只能有 1 个 <root> 标签!

<?xml version"1.0" encoding"UTF-8"?> <configuration> <!-- 路径 --> <property name"PATH" value"./log/open"/> <!-- 控制台输出 --> <appender name"STDOUT" class"ch.qos.lo…...

Skywire蜂窝模组TCP客户端嵌入式框架解析

1. 项目概述klevebrand-skywire-framework-tcp-client是由 Klevebrand 公司开发的轻量级嵌入式 TCP 客户端框架&#xff0c;专为 Skywire&#xff08;Airgain&#xff09;系列蜂窝调制解调器设计。该框架并非通用 TCP 协议栈实现&#xff0c;而是面向特定硬件平台的AT 指令驱动…...