控制循环速度

3 投票
3 回答
4205 浏览
提问于 2025-04-18 03:58

我现在在大学学物理,同时也在学习Python,算是一个小爱好。

为了同时练习这两样,我想写一个简单的“物理引擎”,用来根据x、y和z坐标计算物体的运动。我现在只打算把运动结果以文字形式输出(至少目前是这样!),但我希望位置的更新是实时的。

为此,我需要每秒更新物体的位置大约一百次,并把它打印到屏幕上。所以每10毫秒程序就要打印一次当前的位置。

假设计算执行需要2毫秒,那么循环就得等8毫秒,才能打印并重新计算下一个位置。

那么,构建这样一个循环的最佳方法是什么呢?每秒100次更新频率合适吗,还是说你觉得应该慢一点,比如每秒25次?

3 个回答

1

这里有个警告。你可能不能在一个非实时系统上期待实时的反应。sleep这一类的调用保证你至少会等待一段时间,但实际上可能会让你等得更久。

所以,一旦你从睡眠状态中返回,记得查询一下当前时间,然后再进行“未来”的计算(要考虑到计算所花的时间)。

2

因为你无法提前知道每次循环会花多长时间,所以你需要一种事件驱动的循环方式。一个可能的解决方案是使用 twisted 模块,它是基于一种叫做反应器模式的设计。

from twisted.internet import task
from twisted.internet import reactor

delay = 0.1

def work():
    print "called"

l = task.LoopingCall(work)
l.start(delay)

reactor.run()

不过,正如之前提到的,不要指望它能真正做到实时响应。

2

在Python中,最基本的等待方法是先用import time导入时间模块,然后使用time.sleep来让程序暂停一段时间。那么问题来了,暂停多久呢?这就要看你想怎么处理循环中错过的时间了。下面的实现方式会尝试在错过目标时间后赶上去。

import time
import random

def doTimeConsumingStep(N):
    """
    This represents the computational part of your simulation.

    For the sake of illustration, I've set it up so that it takes a random
    amount of time which is occasionally longer than the interval you want.
    """
    r = random.random()
    computationTime = N * (r + 0.2)
    print("...computing for %f seconds..."%(computationTime,))
    time.sleep(computationTime)


def timerTest(N=1):
    repsCompleted = 0
    beginningOfTime = time.clock()

    start = time.clock()
    goAgainAt = start + N
    while 1:
        print("Loop #%d at time %f"%(repsCompleted, time.clock() - beginningOfTime))
        repsCompleted += 1
        doTimeConsumingStep(N)
        #If we missed our interval, iterate immediately and increment the target time
        if time.clock() > goAgainAt:
            print("Oops, missed an iteration")
            goAgainAt += N
            continue
        #Otherwise, wait for next interval
        timeToSleep = goAgainAt - time.clock()
        goAgainAt += N
        time.sleep(timeToSleep)

if __name__ == "__main__":
    timerTest()

要注意的是,在普通的操作系统上,你肯定会错过你想要的时间,所以像这样的处理是很有必要的。即使使用像tulip和twisted这样的异步框架,在普通操作系统上也无法保证时间的准确性。

撰写回答