18

我正在用 Python 和 C 编写一个带有一些复杂物理模拟算法的科学程序。在实现算法之后,我发现有很多可能的优化来提高性能。常见的是预先计算值,使计算脱离循环,用更复杂的矩阵算法替换简单的矩阵算法等。但是出现了一个问题。未经优化的算法要慢得多,但它的逻辑和与理论的联系看起来更加清晰易读。此外,扩展和修改优化算法也更加困难。

所以,问题是——在提高性能的同时,我应该使用什么技术来保持可读性?现在我试图保持快速和清晰的分支并并行开发它们,但也许有更好的方法?

4

4 回答 4

15

就像一般评论(我对 Python 不太熟悉):我建议您确保可以轻松地将“参考实现”的慢速部分与“优化”部分交换(例如,使用类似Strategy图案)。

这将允许您交叉验证更复杂算法的结果(以确保您没有弄乱结果),并将保持模拟算法的整体结构清晰(关注点分离)。您可以将优化的算法放入单独的源文件/文件夹/包中,并根据需要详细记录它们。

除此之外,尽量避免常见的陷阱:不要进行过早的优化(检查它是否真的值得,例如使用分析器),不要重新发明轮子(寻找可用的库)。

于 2011-09-04T17:52:23.803 回答
3

你的问题是一个非常好的问题,几乎在每一段代码中都会出现,无论是简单还是复杂,都是由任何想称自己为专业人士的程序员编写的。

我试图记住并牢记,新阅读我的代码的读者对问题的粗略看法和我最初拥有的相同直接(可能是蛮力)方法。然后,随着我对问题的深入理解和解决方案的路径变得更加清晰,我尝试写出反映更好理解的评论。我有时会成功,这些评论对读者有帮助,尤其是当我六周后回到代码时,它们对我很有帮助。无论如何,我的风格是写大量评论,当我不写评论时(因为:突然的洞察力让我兴奋;我想看到它运行;我的大脑被炸了),我几乎总是在以后非常后悔。

如果我可以维护两个并行代码流,那就太好了:天真的方式和更复杂的优化方式。但我从来没有成功过。

对我来说,最重要的是,如果我能写出清晰、完整、简洁、准确和最新的评论,那就是我能做的最好的了。

还有一件你已经知道的事情:优化通常并不意味着将大量代码硬塞到一个源代码行上,也许是通过调用一个函数,其参数是另一个函数,其参数是另一个函数,其参数是另一个函数。我知道有些人这样做是为了避免暂时存储函数的值。但是它对加速代码的作用很小(通常什么都没有),而且它是一个婊子。你没有消息,我知道。

于 2011-09-04T17:56:18.030 回答
3

通常假设您必须放弃可读性才能获得性能。

不一定如此。

您需要找出花费大量时间在做什么,为什么

请注意,我没有说您需要进行任何测量。

这是我的意思的一个例子。

很有可能您可以进行一些简单的更改以避免浪费运动,但在程序本身告诉您要修复的内容之前不要修复任何东西。

于 2011-09-04T22:22:47.723 回答
1
def whatYouShouldDo(servings, integration_method=oven):
    """
        Make chicken soup
    """
    # Comments:
    # They are important. With some syntax highlighting, the comments are
    # the first thing a new programmer will look for. Therefore, they should
    # motivate your algorithm, outline it, and break it up into stages.
    # You can MAKE IT FEEL AS IF YOU ARE READING TEXT, interspersing code
    # amongst the text.
    #
    # Algorithm overview:
    # To make chicken soup, we will acquire chicken broth and some noodles.
    # Preprocessing ingredients is done to optimize cooking time. Then we 
    # will output in SOUP format via stdout.
    #
    # BEGIN ALGORITHM
    #
    # Preprocessing:
    # 1. Thaw chicken broth.
    broth = chickenstore.deserialize()

    # 2. Mix with noodles
    if not noodles in cache:
        with begin_transaction(locals=poulty) as t:
            cache[noodles] = t.buy(noodles)  # get from local store
    noodles = cache[noodles]

    # 3. Perform 4th-order Runge-Kutta numerical integration
    import kitchensink import *  # FIXME: poor form, better to from kitchensink import pan at beginning
    result = boilerplate.RK4(broth `semidirect_product` noodles)

    # 4. Serve hot
    log.debug('attempting to serve')
    return result
    log.debug('server successful')

另见http://en.wikipedia.org/wiki/Literate_programming#Example

我还听说这是http://en.wikipedia.org/wiki/Aspect-orienting_programming试图提供的帮助,尽管我还没有真正研究过。(这似乎是一种奇特的说法,即“将您的优化和调试以及其他垃圾放在您正在编写的函数之外”。)

于 2011-09-04T22:35:24.313 回答