Dirty Flag 模式及其应用
之前在开发中就发现“dirty”是一种不错的解决方案:可以用来延缓计算或者避免不必要的计算。后来在想,这应该也算一种设计模式吧,于是搜索“Dirty设计模式”,没有什么结果,然后换成英文“Dirty design pattern”,搜到了《game programming patterns》这本电子书。书中介绍了Dirty Flag 模式在游戏客户端的应用场景,如果英文不好,这里也有中文翻译。本文结合几个具体的例子,介绍什么是Dirty Flag 模式,并分析该模式的适用场景以及使用注意事项。
什么是Dirty Flag:
简单来说,就是用一个标志位(flag)来表示一组数据的状态,这些数据要么是用来计算,或者用来需要同步。在满足条件的时候设置标志位,然后需要的时候检查(check)标志位。如果设置了标志位,那么表示这组数据处于dirty状态,这个时候需要重新计算或者同步。如果flag没有被设置,那么可以不计算(或者利用缓存的计算结果)。另外,在两次check之间,即使有多次标志位的设置,也只需要计算一次。
因此,Dirty Flag模式的本质作用在于:延缓计算或数据同步,甚至减少无谓的计算或者同步。计算比较容易理解,对于同步,后面也会给出例子。在后面的描述中,除非特殊说明,计算也包含了同步。
Dirty Flag使用实例:
首先,《game programming pattern》中的例子非常形象生动,图文并茂,建议直接阅读原文,本文不再复述。接下来介绍几个其他的例子。
First
def set_need_tick(self, is_need):
self.need_tick = is_need def tick(self):
if self.need_tick:
self.do_tick() # do_tick 需要做大量的检查,较为耗时
def dummy_tick(self):
pass
def set_need_tick(self, is_need):
if is_need:
self.tick = self.do_tick
else:
self.tick = self.dummy_tick
Second
class cached_property(object):
""" A property that is only computed once per instance and then replaces
itself with an ordinary attribute. Deleting the attribute resets the
property. """ def __init__(self, func):
update_wrapper(self, func)
self.func = func def __get__(self, obj, cls):
if obj is None: return self
value = obj.__dict__[self.func.__name__] = self.func(obj)
return value
def set_property_dirty(self, property_name):
self.__dict__.pop(property_name, None)
在需要的时候调用这个设置函数就行了,在这个例子中,并没有对某个属性的设置和检查,但配合之前的cached_property,作用是很明显的:缓存计算结果,需要的时候重新计算。下面是完整测试代码
import functools, time
class cached_property(object):
""" A property that is only computed once per instance and then replaces
itself with an ordinary attribute. Deleting the attribute resets the
property. """ def __init__(self, func):
functools.update_wrapper(self, func)
self.func = func def __get__(self, obj, cls):
if obj is None: return self
value = obj.__dict__[self.func.__name__] = self.func(obj)
return value class TestClz(object):
@cached_property
def complex_calc(self):
print 'very complex_calc'
return sum(range(100)) def __set_property_dirty(self, property_name = 'complex_calc'):
self.__dict__.pop(property_name, None) def some_action_effect_property(self):
self.__set_property_dirty() if __name__=='__main__':
t = TestClz()
print '>>> first call'
print t.complex_calc
print '>>> second call'
print t.complex_calc
print '>>>third call'
t.some_action_effect_property()
print t.complex_calc
cache property and dirty
Third
Fourth
Fifth
适用场景:
使用条件:
注意事项:
Dirty Flag 模式及其应用的更多相关文章
- lazy ideas in programming
lazy形容词,懒惰的,毫无疑问是一个贬义词.但是,对于计算机领域,lazy却是非常重要的优化思想:把任务推迟到必须的时刻,好处是避免重复计算,甚至不计算.本文的目的是抛砖引玉,总结一些编程中的laz ...
- python性能优化
注意:本文除非特殊指明,”python“都是代表CPython,即C语言实现的标准python,且本文所讨论的是版本为2.7的CPython. python为什么性能差: 当我们提到一门编程语言的 ...
- lazy ideas in programming(编程中的惰性思想)
lazy形容词,懒惰的,毫无疑问是一个贬义词.但是,对于计算机领域,lazy却是非常重要的优化思想:把任务推迟到必须的时刻,好处是避免重复计算,甚至不计算.本文的目的是抛砖引玉,总结一些编程中的laz ...
- Redis——学习之路二(初识redis服务器命令)
上一章我们已经知道了如果启动redis服务器,现在我们来学习一下,以及如何用客户端连接服务器.接下来我们来学习一下查看操作服务器的命令. 服务器命令: 1.info——当前redis服务器信息 s ...
- 【redis使用全解析】常见运维操作
作者:gnuhpc 出处:http://www.cnblogs.com/gnuhpc/ 1.1 启动 1.1.1 启动redis $ redis-server redis.conf 常见选项: ./r ...
- Unity ShaderLab学习总结
http://www.jianshu.com/p/7b9498e58659 Unity ShaderLab学习总结 Why Bothers? 为什么已经有ShaderForge这种可视化Shader编 ...
- Inside of Jemalloc
INSIDE OF JEMALLOCThe Algorithm and Implementation of Jemalloc author: vector03mail: mmzsmm@163.co ...
- cocod2d-x 之 CCDirector、CCScene、CCSprite
CCDirector是控制游戏流程的主要组件. typedef enum { /// sets a 2D projection (orthogonal projection)2D投机模式 kCCDir ...
- 查看Redis信息和状态
原文转自:http://redisdoc.com/server/info.html INFO [section] 以一种易于解释(parse)且易于阅读的格式,返回关于 Redis 服务器的各种信息和 ...
随机推荐
- CKeditor使用js验证不得为空
if (CKEDITOR.instances.TextArea1.getData() == '') { alert('警告:详细内容不得为空!'); CKEDITOR.instances.TextAr ...
- 百度api集合!
百度 api集市免费接口 IP地址查询 http://apistore.baidu.com/apiworks/servicedetail/114.html 频道新闻API_易源 http://apis ...
- 1)Java学习笔记:接口和抽象类的异同
Java接口和抽象类很像,他们有哪些相同点和异同点呢,下面我们做一个小结 相同 ① 都不能被实例化,都位于继承树的顶端,用于被实现或者继承 ② 都可以包含抽象方法,实现接口或者继承抽象类的普通子类都必 ...
- 在MVC中添加拦截器实现登录后的权限验证
1.新建一个类 (以下实现了打印日志功能) using System; using System.Collections.Generic; using System.Linq; using Syste ...
- java系列-JDBC的封装
参考:http://blog.csdn.net/liuhenghui5201/article/details/16369773 一. 1.加载驱动-->>封装 --->> ...
- java中String相等问题
java中判断两个字符串是否相等的问题 判断两个字符串是否相等的问题.在编程中,通常比较两个字符串是否相同的表达式是"==",但在java中不能这么写.在java中,用的是eq ...
- codeforces 755D. PolandBall and Polygon
D. PolandBall and Polygon time limit per test 4 seconds memory limit per test 256 megabytes input st ...
- php redis 函数手册
Redis::__construct构造函数$redis = new Redis();connect, open 链接redis服务参数host: string,服务地址port: int,端口号ti ...
- LNMP 快速安装
网址是:http://lnmp.org/install.html 值得注意的是:它基本上把所有的扩展都装上了,有点冗余 安装完成后,根目录的位置是 /home/wwwroot/default LNMP ...
- QT第三天学习
回顾: 布局: 绝对位置法: 手工布局:QLayout 可视化布局:设计器 VB MFC JAVA C# cocos QT信号和槽 ---------------------------------- ...