我有一个性能问题,导致测试->代码->测试周期非常慢。慢是很难避免的,因为我正在做一些繁重的图像处理,并且我试图通过在不需要的时候不运行函数来加速一些事情。对于示例:从大图像中计算一些数字,->序列化文本文件中的结果,->从文本文件中恢复计算。
目前,我提交了包含结果的文本文件,以便与团队共享结果,并让其他人快速运行测试。但是,我必须确保每当更新一个依赖项(src图像、预处理函数等)时,就会重新计算这些值。我寻找了一个工具,它允许我描述依赖关系和生产规则,从而使流程自动化,并避免在代码库中提交数据。我想过makefile,但我读了很多反对它的负面建议。我找到了像Scons和其他构建自动化工具这样的东西,但它们是用于构建软件的,而且它们似乎不适合我的任务。
我决定编写一个小库来解决这个问题(我的环境主要是Python和一些C)。目标是让对象知道它们自己的输出的生产规则,并知道它们所依赖的其他对象。对象通过比较文件的当前MD5校验和(存储在一个小临时文件中的某个地方)来知道它的输出是否是最新的。
我在这里重新发明了一个轮子吗?是否有我应该使用的工具而不是自定义库?如果不是,这是否解决这个问题的好模式?
import os
import path
from md5 import md5 as stdMd5
# path.root is the root of our repo
hashDir = os.path.join(path.root, '_hashes')
def md5(toHash):
return stdMd5(toHash).hexdigest()
class BaseRule(object):
'''base object, managing work like checking if results are up to date, and
calling production rules if they are not'''
outPath = None
def __init__(self, func):
self.func = func
@property
def hashPath(self):
return os.path.join(hashDir, md5(self.outPath))
def getOutHash(self):
with open(self.outPath) as f:
fileHash = md5(f.read())
return fileHash
def isUpToDate(self):
if not os.path.exists(self.outPath):
return False
if not os.path.exists(self.hashPath):
return False
with open(self.outPath) as f:
fileHash = self.getOutHash()
with open(self.hashPath) as f:
storedHash = f.read().strip()
return storedHash == fileHash
def storeHash(self):
if not os.path.exists(hashDir):
os.makedirs(hashDir)
with open(self.hashPath, 'w') as f:
f.write(self.getOutHash())
def get(self):
inputPathes = dict([(key, inp.get()) for key, inp in self.inputs.items()])
if not self.isUpToDate():
self.func(outPath=self.outPath, **inputPathes)
self.storeHash()
return self.outPath
class StableSrc(BaseRule):
'source file that never change'
inputs = {}
def __init__(self, path):
self.outPath = path
def isUpToDate(self):
return True
def rule(_inputs, _outPath):
'decorator used to declare dependencies'
class Rule(BaseRule):
inputs = _inputs
outPath = _outPath
return Rule
def copyTest():
'test function'
import shutil
@rule({'inp' : StableSrc('test.txt')}, 'test2.txt')
def newTest(inp, outPath):
print 'copy'
shutil.copy(inp, outPath)
@rule({'inp' : newTest}, 'test3.txt')
def newNewTest(inp, outPath):
print 'copy2'
shutil.copy(inp, outPath)
return newNewTest.get()
if __name__ == '__main__':
copyTest() # will copy test.txt to test2.txt and test3.txt. If ran a second time, won't copy anything发布于 2011-09-20 12:32:23
# path.root is the root of our repo
hashDir = os.path.join(path.root, '_hashes')Python样式指南建议全局常量为ALL_CAPS。
class BaseRule(object):
'''base object, managing work like checking if results are up to date, and
calling production rules if they are not'''
outPath = NonePython样式指南建议类级常量为ALL_CAPS。
def isUpToDate(self):
if not os.path.exists(self.outPath):
return False
if not os.path.exists(self.hashPath):
return False
with open(self.outPath) as f:
fileHash = self.getOutHas()您不使用在这里打开的文件,而是在getOutHash中打开该文件
with open(self.hashPath) as f:
storedHash = f.read().strip()
return storedHash == fileHash
def get(self):
inputPathes = dict([(key, inp.get()) for key, inp in self.inputs.items()])不需要方括号。他们这样做是为了让它产生一个清单。但是,由于您正在创建一个字典,所以没有必要先列出一个列表。
if not self.isUpToDate():
self.func(outPath=self.outPath, **inputPathes)
self.storeHash()
return self.outPath
class StableSrc(BaseRule):
'source file that never change'
inputs = {}我知道您永远不会修改它,但是输入是上面的一个对象级别的属性,如果保持这样的话,它是最清晰的。
def __init__(self, path):
self.outPath = path
def isUpToDate(self):
return True
def copyTest():
'test function'
import shutil
@rule({'inp' : StableSrc('test.txt')}, 'test2.txt')
def newTest(inp, outPath):
print 'copy'
shutil.copy(inp, outPath)通常,您有少量可能的操作,每次使用都有不同的输入/输出。您的装饰方法假设每个操作都不同。
https://codereview.stackexchange.com/questions/4920
复制相似问题