首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >更快的依赖分析测试

更快的依赖分析测试
EN

Code Review用户
提问于 2011-09-20 12:00:36
回答 1查看 198关注 0票数 5

我有一个性能问题,导致测试->代码->测试周期非常慢。慢是很难避免的,因为我正在做一些繁重的图像处理,并且我试图通过在不需要的时候不运行函数来加速一些事情。对于示例:从大图像中计算一些数字,->序列化文本文件中的结果,->从文本文件中恢复计算。

目前,我提交了包含结果的文本文件,以便与团队共享结果,并让其他人快速运行测试。但是,我必须确保每当更新一个依赖项(src图像、预处理函数等)时,就会重新计算这些值。我寻找了一个工具,它允许我描述依赖关系和生产规则,从而使流程自动化,并避免在代码库中提交数据。我想过makefile,但我读了很多反对它的负面建议。我找到了像Scons和其他构建自动化工具这样的东西,但它们是用于构建软件的,而且它们似乎不适合我的任务。

我决定编写一个小库来解决这个问题(我的环境主要是Python和一些C)。目标是让对象知道它们自己的输出的生产规则,并知道它们所依赖的其他对象。对象通过比较文件的当前MD5校验和(存储在一个小临时文件中的某个地方)来知道它的输出是否是最新的。

我在这里重新发明了一个轮子吗?是否有我应该使用的工具而不是自定义库?如果不是,这是否解决这个问题的好模式?

代码语言:javascript
复制
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
EN

回答 1

Code Review用户

回答已采纳

发布于 2011-09-20 12:32:23

代码语言:javascript
复制
# path.root is the root of our repo
hashDir = os.path.join(path.root, '_hashes')

Python样式指南建议全局常量为ALL_CAPS。

代码语言:javascript
复制
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

Python样式指南建议类级常量为ALL_CAPS。

代码语言:javascript
复制
    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中打开该文件

代码语言:javascript
复制
        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()])

不需要方括号。他们这样做是为了让它产生一个清单。但是,由于您正在创建一个字典,所以没有必要先列出一个列表。

代码语言:javascript
复制
        if not self.isUpToDate():
            self.func(outPath=self.outPath, **inputPathes)
            self.storeHash()
        return self.outPath

class StableSrc(BaseRule):
    'source file that never change'

    inputs = {}

我知道您永远不会修改它,但是输入是上面的一个对象级别的属性,如果保持这样的话,它是最清晰的。

代码语言:javascript
复制
    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)

通常,您有少量可能的操作,每次使用都有不同的输入/输出。您的装饰方法假设每个操作都不同。

  1. 您没有跟踪规则之间的依赖关系。因此,您不能有一些像.swig生产.cpp produces .o这样的产品,它与生产.exe链接在一起
  2. 为每个规则创建一个类是很奇怪的。为每个规则创建一个对象会更有意义。
  3. 唯一能克服makefile的是使用散列,而不是时间戳
票数 2
EN
页面原文内容由Code Review提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://codereview.stackexchange.com/questions/4920

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档