0

0

总结一些编码和设计原则实例

零下一度

零下一度

发布时间:2017-06-24 10:36:27

|

1949人浏览过

|

来源于php中文网

原创

本章介绍了本书其它部分未涉及到的一些编码和设计原则。包含了一些.net的应用场景,有些不会造成太大危害,有些则会造成明显的问题。剩下的则根据你的使用方法会产生不同的效果。如果要对本章节出现的原则做一个总结,那就是:

过度的优化会影响代码的抽象
这意味着,当你希望更高的优化性能,你需要了解每个层次代码的实现细节。本章会有很多相关介绍。

类 vs 结构体

类的实例都是在堆上分配的,通过指针的引用进行访问。传递这些对象代价很低,因为它只是一个指针(4或者8直接)的拷贝。然而,对象也有一些固定开销:8或16字节(32或64位系统)。这些开销包括指向方法表的指针和用于其它目的同步字段。但是,如果通过调试工具查看一个空对象占用的内存,这会发现大了13或者24字节(32位或64位系统)。这是.NET的内存对齐机制导致的。

而结构体则没上面的开销,它的内存使用量就是字段大小的综合。如果结构体是方法(函数)里声明的局部变量,则它在堆栈上分配控件。如果结构体被声明为类的一部分,这结构体使用的内存这是该类的内存布局里的一部分(因此它会分配在堆上)。但你将结构体传递给方法(函数)时,他将对字节数据做复制。因为它不在堆上,结构体是不会导致垃圾回收的。

因此这里有一个折中。你可以找到各种关于结构体尺寸大小的建议,但这里我不会告诉你一个确切的数字。在大多数情况下,你结构体需要保持一个比较小的尺寸,特别是他们需要经常被传递,你需要保证结构体的大小不会造成太大的问题。唯一能确定的是,你需要根据自己的应用场景进行分析。

有些情况下,效率的差别还是蛮大的。当一个对象开销看起来不是很多,但是对比一个对象数组和结构体数组就可以看出差别。在32位系统下,假设一个数据结构包含16字节的数据,数组长度是100w。
使用对象数组占用的空间
8字节数组开销+
(4字节指针地址X1,000,000)+
((8字节头部+16字节数据)X1,000,000)
=28MB

使用结构体数组占用的空间
8字节数组开销+
(16字节数据X1,000,100)
=16MB

如果使用64位系统,对象数组则使用40MB,而结构体数组仍然是16MB。
可以看到,在一个结构数组中,相同大小的数据占用的内存小。随着对象数组里对象的增加,还会增加GC的压力。
除了空间,还有CPU效率问题。CPU有多级缓存。越靠近CPU的缓存越小,但访问速度也会更快,对于顺序保存的数据越容易优化。
对于一个结构体数组,他们在内存里都是连续的值。访问结构体数组里数据很简单,只要找到正确的位置就可以得到对应的值。这就意味着在大数组数据做迭代访问有巨大的差异。如果该值已经在CPU的告诉缓存中,它的访问速度是要比访问RAM要快一个数量级。

如果要访问对象数组里的某一项,需要先获得该对象的指针引用,再去堆里访问。迭代对象数组的时候,就会造成数据指针在堆里跳转,频繁更新CPU的缓存,进而浪费了很多访问CPU缓存数据机会。

ThinkPHP3.2.3完全开发
ThinkPHP3.2.3完全开发

ThinkPHP是一个快速、简单的基于MVC和面向对象的轻量级PHP开发框架,遵循Apache2开源协议发布,从诞生以来一直秉承简洁实用的设计原则,在保持出色的性能和至简的代码的同时,尤其注重开发体验和易用性,并且拥有众多的原创功能和特性,为WEB应用开发提供了强有力的支持。 3.2版本则在原来的基础上进行一些架构的调整,引入了命名空间支持和模块化的完善,为大型应用和模块化开发提供了更多的便利。

下载

在很多时候,通过改进数据保存在内存的位置,降低CPU访问内存的开销是使用结构体的一个主要原因,它可以显著的提升性能。

因为结构体使用的时候总是被复制,所以编码时要很小心,否则你会产生一些有趣的bug。例如下面的栗子,你是无法通过编译的:

struct Point
{
    public int x;
    public int y;
}

public static void Main()
{
    List points = new List();
    points.Add(new Point() {x = 1, y = 2});
    points[0].x = 3;
}

问题是在最后一行,你试图修改列表里Point元素的某个值,这个操作是不行的,因为points[0]返回的是原始值的一个副本。正确的修改值的方式是

Point p = points[0];
p.x = 3;
points[0] = p;

但是,你可以采取更严格的编码策略:不要修改结构体。一旦结构体创建,永远不要改变他的值。这可以消除了上面的编译问题,并简化了结构体的使用规则。
我之前提到,结构体应该保持小的体积,已避免花费大量的时间来复制他们,但是偶尔也会使用一些大的结构体。例如一个最终商业流程细节的对象,里面需要保存大量的时间戳:

class Order
{
    public DateTime ReceivedTime { get; set; }

    public DateTime AcknowledgeTime { get; set; }
    public DateTime ProcessBeginTime { get; set; }
    public DateTime WarehouseReceiveTime { get; set; }
    public DateTime WarehouseRunnerReceiveTime { get; set; }
    public DateTime WarehouseRunnerCompletionTime { get; set; }
    public DateTime PackingBeginTime { get; set; }
    public DateTime PackingEndTime { get; set; }
    public DateTime LabelPrintTime { get; set; }
    public DateTime CarrierNotifyTime { get; set; }
    public DateTime ProcessEndTime { get; set; }
    public DateTime EmailSentToCustomerTime { get; set; }
    public DateTime CarrerPickupTime { get; set; }
    // lots of other data ... 
}

为了简化代码,我们可以将时间的数据划分到自己的子结构里,这样我们可以通过这样的方式访问Order对象:

Order order = new Order(); 
Order.Times.ReceivedTime = DateTime.UtcNow;

我们可以把数据全部放到自己的类里:

class OrderTimes
    {
        public DateTime ReceivedTime { get; set; }
        public DateTime AcknowledgeTime { get; set; }
        public DateTime ProcessBeginTime { get; set; }
        public DateTime WarehouseReceiveTime { get; set; }
        public DateTime WarehouseRunnerReceiveTime { get; set; }
        public DateTime WarehouseRunnerCompletionTime { get; set; }
        public DateTime PackingBeginTime { get; set; }
        public DateTime PackingEndTime { get; set; }
        public DateTime LabelPrintTime { get; set; }
        public DateTime CarrierNotifyTime { get; set; }
        public DateTime ProcessEndTime { get; set; }
        public DateTime EmailSentToCustomerTime { get; set; }
        public DateTime CarrerPickupTime { get; set; }
    }

    class Order
    {
        public OrderTimes Times;
    }

但是,这样会为每个Order对象引入额外的12或者24字节的开销。如果你需要将OrderTimes对象作为一个整体传入各种方法函数里,这也许是有一定道理的,但为什么不把Order对象传入方法里呢?如果你同时有数千个Order对象,则可能会导致更多的垃圾回收,这是额外的对象增加的引用导致的。
相反,将OrderTime更改为结构体,通过Order上的属性(例如:Order.Times.ReceivedTime)访问OrderTImes结构体的各个属性,不会导致结构体的副本(.NET会对这个访问做优化)。这样OrderTimes结构体基本上成为Order类的内存布局的一部分,几乎和没有子结构体一样了,你拥有了更加漂亮的代码。
这种技术确实违反了不可变的结构体原理,但这里的技巧就是将OrderTimes结构的字段视为Order对象的字段。你不需要将OrderTimes结构体作为一个实体进行传递,它只是一个代码组织方式。

热门AI工具

更多
DeepSeek
DeepSeek

幻方量化公司旗下的开源大模型平台

豆包大模型
豆包大模型

字节跳动自主研发的一系列大型语言模型

通义千问
通义千问

阿里巴巴推出的全能AI助手

腾讯元宝
腾讯元宝

腾讯混元平台推出的AI助手

文心一言
文心一言

文心一言是百度开发的AI聊天机器人,通过对话可以生成各种形式的内容。

讯飞写作
讯飞写作

基于讯飞星火大模型的AI写作工具,可以快速生成新闻稿件、品宣文案、工作总结、心得体会等各种文文稿

即梦AI
即梦AI

一站式AI创作平台,免费AI图片和视频生成。

ChatGPT
ChatGPT

最最强大的AI聊天机器人程序,ChatGPT不单是聊天机器人,还能进行撰写邮件、视频脚本、文案、翻译、代码等任务。

相关专题

更多
包子漫画网页版入口与全集阅读指南_正版免费漫画快速访问方法
包子漫画网页版入口与全集阅读指南_正版免费漫画快速访问方法

本专题汇总了包子漫画官网和网页版入口,提供最新章节抢先看方法、正版免费阅读指南,以及稳定访问方式,帮助用户快速直达包子漫画页面,无广告畅享全集漫画内容。

40

2026.02.10

MC.JS网页版快速畅玩指南_MC.JS官网在线入口及免安装体验方法
MC.JS网页版快速畅玩指南_MC.JS官网在线入口及免安装体验方法

本专题汇总了MC.JS官网入口和网页版快速畅玩方法,提供免安装访问、不同版本(1.8.8、1.12.8)在线体验指南,以及正版网页端操作说明,帮助玩家轻松进入MC.JS世界,实现即时畅玩与高效体验。

24

2026.02.10

谷歌邮箱网页版登录与注册全指南_Gmail账号快速访问与安全操作教程
谷歌邮箱网页版登录与注册全指南_Gmail账号快速访问与安全操作教程

本专题汇总了谷歌邮箱网页版的最新登录入口和注册方法,详细提供官方账号快速访问方式、网页版操作教程及安全登录技巧,帮助用户轻松管理Gmail邮箱账户,实现高效、安全的邮箱使用体验。

21

2026.02.10

铁路12306订票与退改全攻略_高效购票与座位选取技巧
铁路12306订票与退改全攻略_高效购票与座位选取技巧

本专题全面汇总铁路12306订票、退票、改签及候补订单操作技巧,提供车厢座位分布参考、抢票攻略和高铁安检注意事项,帮助新手用户快速掌握高效购票与退改流程,提高出行效率和体验。

16

2026.02.10

TensorFlow2深度学习模型实战与优化
TensorFlow2深度学习模型实战与优化

本专题面向 AI 与数据科学开发者,系统讲解 TensorFlow 2 框架下深度学习模型的构建、训练、调优与部署。内容包括神经网络基础、卷积神经网络、循环神经网络、优化算法及模型性能提升技巧。通过实战项目演示,帮助开发者掌握从模型设计到上线的完整流程。

0

2026.02.10

Vue3组合式API与组件开发实战
Vue3组合式API与组件开发实战

本专题讲解 Vue 3 组合式 API 的核心概念与应用技巧,深入分析响应式系统、生命周期管理、组件设计与复用策略。通过完整项目案例,指导前端开发者实现高性能、结构清晰的 Vue 应用,提升开发效率与代码可维护性。

4

2026.02.10

Go语言微服务架构与gRPC实战
Go语言微服务架构与gRPC实战

本专题面向有 Go 基础的开发者,系统讲解微服务架构设计与 gRPC 的高效应用。内容涵盖服务拆分、RPC 通信、负载均衡、错误处理、服务注册与发现等关键技术。通过实战案例,帮助开发者搭建高性能、可扩展的 Go 微服务系统。

1

2026.02.10

React 18状态管理与Hooks高级实践
React 18状态管理与Hooks高级实践

本专题专注于 React 18 的高级开发技术,详细讲解 useState、useEffect、useReducer、useContext 等 Hooks 的使用技巧,以及 Redux、Zustand 等状态管理工具的集成与优化方法。通过真实案例,帮助前端开发者构建可维护、性能优良的现代 React 应用。

4

2026.02.10

Node.js后端开发与Express框架实践
Node.js后端开发与Express框架实践

本专题针对初中级 Node.js 开发者,系统讲解如何使用 Express 框架搭建高性能后端服务。内容包括路由设计、中间件开发、数据库集成、API 安全与异常处理,以及 RESTful API 的设计与优化。通过实际项目演示,帮助开发者快速掌握 Node.js 后端开发流程。

2

2026.02.10

热门下载

更多
网站特效
/
网站源码
/
网站素材
/
前端模板

精品课程

更多
相关推荐
/
热门推荐
/
最新课程
C# 教程
C# 教程

共94课时 | 9万人学习

python编程入门系列图文教程
python编程入门系列图文教程

共65课时 | 24.8万人学习

vscode其实很简单
vscode其实很简单

共72课时 | 29.2万人学习

关于我们 免责申明 举报中心 意见反馈 讲师合作 广告合作 最新更新
php中文网:公益在线php培训,帮助PHP学习者快速成长!
关注服务号 技术交流群
PHP中文网订阅号
每天精选资源文章推送

Copyright 2014-2026 https://www.php.cn/ All Rights Reserved | php.cn | 湘ICP备2023035733号