05_对象性能模式

对象性能模式

面向对象很好地解决了“抽象”的问题,但是必不可免地要付出定的代价。对于通常情况来讲,面向对象的成本大都可以忽略计。但是某些情况,面向对象所带来的成本必须谨慎处理。

典型模型:

  • Singleton
  • Flyweight

Singleton 单件模式

保证一个类仅有一个实例,并提供一个该实例的全局访问点。

动机

  • 在软件系统中,经常有这样一些特殊的类,必须保证它们在系统中只存在一个实例,才能确保它们的逻辑正确性、以及良好的效率。
  • 如何绕过常规的构造器,提供一种机制来保证一个类只有一个实例?
  • 这应该是类设计者的责任,而不是使用者的责任。

就只需要一个实例,

例子

import "fmt"type Singleton struct {Name string
}var instance *Singleton// 线程不安全版本
func (self *Singleton) getInstance() *Singleton {if instance == nil {//多个线程的话,可能会实例化多次instance = &Singleton{}fmt.Println("Nil")}return instance
}

线程安全版本一,高并发场景不适合,

var lock sync.Mutex
var once = &sync.Once{}// 线程安全版
// 方法一:加锁
// 但成本高,每次访问都需要获取锁,就算已经不是nil了,此时每次还是需要获取锁阻塞。
func (self *Singleton) getInstance() *Singleton {lock.Lock()if instance == nil { //多个线程的话,可能会实例化多次instance = &Singleton{}fmt.Println("Nil")}lock.Unlock()return instance
}

解决方法二

// 方法二:双检查锁
// 两个检查锁,只有第一次会都阻塞。
// 2000年左右,问题是内存读写的reorder
func (self *Singleton) getInstanceSecure2() *Singleton {if instance == nil { //避免读代价高lock.Lock()if instance == nil {instance = new(Singleton)}lock.Unlock()}return instance
}

对于instacne = new(Signleton)认为的执行顺序:

memory = allocate()//1. 分配内存空间
ctorInstance(memory)//2. 初始化对象,在memory上初始化Singleton对象
instance = memory//3. 设置instance指向分配的地址

但实际上由于多线程和指令优化,可能会是如下过程

memory = allocate()//1. 分配内存空间
instance = memory//3. 设置instance指向分配的地址
ctorInstance(memory)//2. 初始化对象,在memory上初始化Singleton对象

执行到3.然后释放锁,其他对象访问发现不为nil,但实际上是nil因为2还没有初始化,这样访问就会出问题。

方法三:once保证只执行一次

// go 的特殊解法
func (self *Singleton) getInstanceSecure3() *Singleton {if instance == nil {once.Do(func() {instance = &Singleton{}})}return instance
}

总结

在这里插入图片描述

  • Singleton模式一般不要支持拷贝构造函数和Clone接口,因为这有可能导致多个对象实例,与Singleton模式的初衷违背。

  • 如何实现多线程环境下安全的Singleton?注意对双检查锁的正确实现。

Flyweight

运用共享技术有效地支持大量细粒度的对象。

动机

  • 在软件系统采用纯粹对象方案的问题在于大量细粒度的对象会很快充斥在系统中,从而带来很高的运行时代价一主要指内存需求方面的代价。
  • 如何在避免大量细粒度对象问题的同时,让外部客户程序仍然能够透明地使用面向对象的方式来进行操作?

例如字符串,占用内存实际上比较大的,有的是编译器阶段。

问题

package flyweighttype Font struct {FontName string
}// 字体构造函数
func NewFont(name string) *Font {return &Font{FontName: name}
}// 字体工厂
type FontFactory struct {FontPool map[string]*Font //字体资源池,Flyweight的思想体现
}// 获取字体
func (self *FontFactory) GetFont(name string) *Font {if font, ok := self.FontPool[name]; ok {return font} else {font := NewFont(name)self.FontPool[name] = fontreturn font}
}

总结

在这里插入图片描述

  • 面向对象很好地解决了抽象性的问题,但是作为一个运行在机器中的程序实体,我们需要考虑对象的代价问题。Flyweight主要解决面向对象的代价问题,一般不触及面向对象的抽象性问题。
  • Flyweight采用对象共享的做法来降低系统中对象的个数,从而降低细粒度对象给系统带来的内存压力。在具体实现方面,要注意对象状态的处理。一般是只读的
  • 对象的数量太大从而导致对象内存开销加大一一什么样的数量才算大?这需要我们仔细的根据具体应用情况进行评估,而不能凭空臆断。

主要解决面向对象的代价问题,一般不触及面向对象的抽象性问题。

  • Flyweight采用对象共享的做法来降低系统中对象的个数,从而降低细粒度对象给系统带来的内存压力。在具体实现方面,要注意对象状态的处理。一般是只读的
  • 对象的数量太大从而导致对象内存开销加大一一什么样的数量才算大?这需要我们仔细的根据具体应用情况进行评估,而不能凭空臆断。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.hqwc.cn/news/124176.html

如若内容造成侵权/违法违规/事实不符,请联系编程知识网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

大数据Flink(九十六):DML:Deduplication

文章目录 DML:Deduplication DML:Deduplication Deduplication 定义(支持 Batch\Streaming):Deduplication 其实就是去重,也即上文介绍到的 TopN 中 row_number = 1 的场景,但是这里有一点不一样在于其排序字段一定是时间属性列,不能是其他非时间属性的普通列。在 ro…

C# DeOldify 黑白照片 老照片上色

效果 项目 代码 using System; using System.Collections.Generic; using System.ComponentModel; using System.Data; using System.Drawing; using System.Drawing.Imaging; using System.IO; using System.Linq; using System.Reflection; using System.Text; using System…

linux系统的启动流程

目录 简述linux的启动流程 git简介 Linux文件 Ubuntu文件汇总 linux文件属性 Linux命令行 更换软件源 简述linux的启动流程 韦东山课程学习路线:APP应用--DEV驱动--项目。 百问网官网 git资料:https://e.coding.net/weiongshan/01_all_series_qu…

计算机竞赛 行人重识别(person reid) - 机器视觉 深度学习 opencv python

文章目录 0 前言1 技术背景2 技术介绍3 重识别技术实现3.1 数据集3.2 Person REID3.2.1 算法原理3.2.2 算法流程图 4 实现效果5 部分代码6 最后 0 前言 🔥 优质竞赛项目系列,今天要分享的是 🚩 深度学习行人重识别(person reid)系统 该项目…

快速选择排序

"你经过我每个灿烂时刻,我才真正学会如你般自由" 前些天有些无聊,想试试自己写的快排能否过leetcode上的排序算法题。结果是,不用截图可想而知,肯定是没过的,否则也不会有这篇文章的产出。 这份快排算法代码…

【已解决】opencv 交叉编译 ffmpeg选项始终为NO

一、opencv 交叉编译没有 ffmpeg ,会导致视频打不开 在交叉编译时候,发现在 pc 端能用 opencv 打开的视频,但是在 rv1126 上打不开。在网上查了很久,原因可能是 交叉编译过程 ffmpeg 造成的。之前 ffmpeg 是直接用 apt 安装的&am…

KUKA机器人通过3点法设置工作台基坐标系的具体方法

KUKA机器人通过3点法设置工作台基坐标系的具体方法 具体方法和步骤可参考以下内容: 进入主菜单界面,依次选择“投入运行”—“测量”—基坐标,选择“3点法”, 在系统弹出的基坐标编辑界面,给基座标编号为3,命名为table1,然后单击“继续”按钮,进行下一步操作, 在弹出的…

JavaScript系列从入门到精通系列第十三篇:JavaScript中基本数据类型和引用数据类型,创建对象的两种方式

一:基本数据类型与引用数据类型 基本数据类型:String Number Boolean Null Undefined 引用数据类型:Object 我们的内存分成了两大块,一是栈内存二是堆内存。变量都是保存到栈内存中,var a 123; a和123都在栈空间&…

一文拿捏Spring之AOP

Spring 1.Spring的理解 1.狭义上 指SpringFramework,特别的控制反转、依赖注入、面向切面、等特性 2.广义上 Spring家族的一系列产品,像SpringMVC、SpringBoot、SpringCloud等 2.aop 🌟面试题(aop): 简单介绍一下AOP? aop…

HTML之如何下载网页中的音频(二)

简介: CSDN博客专家,专注Android/Linux系统,分享多mic语音方案、音视频、编解码等技术,与大家一起成长! 优质专栏:Audio工程师进阶系列【原创干货持续更新中……】🚀 人生格言: 人生…

【C语言经典100例题-68】有n个整数,使其前面各数顺序向后移m个位置,最后m个数变成最前面的m个数

方法一 将原数组拆成两部分&#xff0c;前面n-m个数和后面m个数。首先将前面n-m个数逆序&#xff0c;然后将后面的m个数逆序。最后将整个数组逆序即可。 #include <stdio.h>void reverse(int arr[], int start, int end) {for (int i start, j end; i < (start en…

CharacterEncodingFilter的用法

CharacterEncoding是SpringMVC提供的一个一个过滤器,用于设置请求和响应的字符编码,解决乱码问题,他本身是一个过滤器 那么在SpringBoot中,CharacterEncoding就有一个很好的秒用 setEncoding("UTF-8")设置编码 setForceEncoding(true) 设置请求和响应编码 还需要在配…