享元模式 - 内存占用
Flyweight pattern - Memory footprint
我正在学习 Python,我认为这是刷新我的模式知识的一个很好的借口,在这种情况下,享元模式。
我创建了两个小程序,一个没有优化,一个正在实现享元模式。出于测试目的,我正在创建一支由 1'000'000 Enemy
个对象组成的军队。每个敌人可以分为三种类型(士兵、忍者或酋长),我为每种类型分配了一个座右铭。
我想检查的是,使用我未优化的程序,我得到了 1'000'000 个敌人,每个敌人都有一个类型和一个 "long" 字符串,其中包含座右铭。
使用优化的代码,我只想创建三个对象 (EnemyType
) 匹配每种类型并且只包含 3 倍的格言字符串。然后,我向每个 Enemy
添加一个成员,指向所需的 EnemyType
。
现在的代码(仅摘录):
未优化的程序
在此版本中,每个敌人都会存储其类型和座右铭。
enemyList = []
enemyTypes = {'Soldier' : 'Sir, yes sir!', 'Ninja' : 'Always behind you !', 'Chief' : 'Always behind ... lot of lines '}
for i in range(1000000):
randomPosX = 0 # random.choice(range(1000))
randomPosY = 0 # random.choice(range(1000))
randomTypeIndex = 0 # random.choice(range(0,len(enemyTypes)))
enemyType = enemyTypes.keys()[randomTypeIndex]
# Here, the type and motto are parameters of EACH enemy object.
enemyList.append(Enemy(randomPosX, randomPosY, enemyType, enemyTypes[enemyType]))
优化程序
在此版本中,每个敌人都有一个 EnemyType
对象的成员,该对象存储其类型和座右铭。仅创建了 EnemyType
的三个实例,我应该会看到对内存占用的影响。
enemyList = []
soldierEnemy = EnemyType('Soldier', 'Sir, yes sir!')
ninjaEnemy = EnemyType('Ninja', 'Always behind you !')
chiefEnemy = EnemyType('Chief', 'Always behind ... lot of lines.')
enemyTypes = {'Soldier' : soldierEnemy, 'Ninja' : ninjaEnemy, 'Chief' : chiefEnemy}
enemyCount = {}
for i in range(1000000):
randomPosX = 0 # random.choice(range(1000))
randomPosY = 0 # random.choice(range(1000))
randomTypeIndex = 0 #random.choice(range(0,len(enemyTypes)))
enemyType = enemyTypes.values()[randomTypeIndex]
# Here, each enemy only has a reference on its type.
enemyList.append(Enemy(randomPosX, randomPosY, enemyType))
现在我正在使用它来获取我的内存占用量(在我的应用程序自行关闭之前的最后几行):
import os
import psutil
...
# return the memory usage in MB
process = psutil.Process(os.getpid())
print process.get_memory_info()[0] / float(2 ** 20)
我的问题是,我看不出我的两个程序的输出有什么不同:
优化 = 384.0859375 Mb
未优化 = 383.40234375 Mb
它是获取内存占用的合适工具吗?我是 Python 的新手,所以我的代码可能有问题,但我在第二个解决方案中检查了我的 EnemyType 对象,我确实只出现了三次。因此,我应该有 3 个座右铭字符串而不是 1'000'000。
我读到过一个名为 Heapy 的工具,用于 Python,这里会更准确吗?
据我从问题中的代码可以看出,在这两种情况下,您只是对相同数量的实例使用引用。
取 "unoptimized" 版本的:
enemyList.append(Enemy(randomPosX, randomPosY, enemyType, enemyTypes[enemyType]))
确实 enemyTypes[enemyType]
是一个字符串,这可能让您认为您有很多字符串实例。但实际上,您的每个对象都有 三个相同的字符串对象之一。
您可以通过比较成员的 id
来检查这一点。做一个ids的set
,看是否大于3。
我正在学习 Python,我认为这是刷新我的模式知识的一个很好的借口,在这种情况下,享元模式。
我创建了两个小程序,一个没有优化,一个正在实现享元模式。出于测试目的,我正在创建一支由 1'000'000 Enemy
个对象组成的军队。每个敌人可以分为三种类型(士兵、忍者或酋长),我为每种类型分配了一个座右铭。
我想检查的是,使用我未优化的程序,我得到了 1'000'000 个敌人,每个敌人都有一个类型和一个 "long" 字符串,其中包含座右铭。
使用优化的代码,我只想创建三个对象 (EnemyType
) 匹配每种类型并且只包含 3 倍的格言字符串。然后,我向每个 Enemy
添加一个成员,指向所需的 EnemyType
。
现在的代码(仅摘录):
未优化的程序
在此版本中,每个敌人都会存储其类型和座右铭。
enemyList = [] enemyTypes = {'Soldier' : 'Sir, yes sir!', 'Ninja' : 'Always behind you !', 'Chief' : 'Always behind ... lot of lines '} for i in range(1000000): randomPosX = 0 # random.choice(range(1000)) randomPosY = 0 # random.choice(range(1000)) randomTypeIndex = 0 # random.choice(range(0,len(enemyTypes))) enemyType = enemyTypes.keys()[randomTypeIndex] # Here, the type and motto are parameters of EACH enemy object. enemyList.append(Enemy(randomPosX, randomPosY, enemyType, enemyTypes[enemyType]))
优化程序
在此版本中,每个敌人都有一个
EnemyType
对象的成员,该对象存储其类型和座右铭。仅创建了EnemyType
的三个实例,我应该会看到对内存占用的影响。enemyList = [] soldierEnemy = EnemyType('Soldier', 'Sir, yes sir!') ninjaEnemy = EnemyType('Ninja', 'Always behind you !') chiefEnemy = EnemyType('Chief', 'Always behind ... lot of lines.') enemyTypes = {'Soldier' : soldierEnemy, 'Ninja' : ninjaEnemy, 'Chief' : chiefEnemy} enemyCount = {} for i in range(1000000): randomPosX = 0 # random.choice(range(1000)) randomPosY = 0 # random.choice(range(1000)) randomTypeIndex = 0 #random.choice(range(0,len(enemyTypes))) enemyType = enemyTypes.values()[randomTypeIndex] # Here, each enemy only has a reference on its type. enemyList.append(Enemy(randomPosX, randomPosY, enemyType))
现在我正在使用它来获取我的内存占用量(在我的应用程序自行关闭之前的最后几行):
import os
import psutil
...
# return the memory usage in MB
process = psutil.Process(os.getpid())
print process.get_memory_info()[0] / float(2 ** 20)
我的问题是,我看不出我的两个程序的输出有什么不同:
优化 = 384.0859375 Mb
未优化 = 383.40234375 Mb
它是获取内存占用的合适工具吗?我是 Python 的新手,所以我的代码可能有问题,但我在第二个解决方案中检查了我的 EnemyType 对象,我确实只出现了三次。因此,我应该有 3 个座右铭字符串而不是 1'000'000。
我读到过一个名为 Heapy 的工具,用于 Python,这里会更准确吗?
据我从问题中的代码可以看出,在这两种情况下,您只是对相同数量的实例使用引用。
取 "unoptimized" 版本的:
enemyList.append(Enemy(randomPosX, randomPosY, enemyType, enemyTypes[enemyType]))
确实 enemyTypes[enemyType]
是一个字符串,这可能让您认为您有很多字符串实例。但实际上,您的每个对象都有 三个相同的字符串对象之一。
您可以通过比较成员的 id
来检查这一点。做一个ids的set
,看是否大于3。