2

我目前正在使用生成器作为获得长流程进度的快速方法,我想知道它通常是如何完成的,因为我发现它不是很优雅......

让我先解释一下,我有一个 engine.py 模块,它执行一些视频处理(分割、bg/fg 减法等),这需要很多时间(从几秒到几分钟)。

我从一个用 wxpython 编写的 GUI 和一个控制台脚本中使用这个模块。当我查看如何在 wxpython 中实现进度对话框时,我看到我必须以某种方式获取进度值来更新我的对话框,这是你承认的纯逻辑......所以我决定使用我的处理的帧数引擎函数,每 33 帧产生当前帧号,并在处理完成时产生 None。

通过这样做,它看起来像这样:

dlg = wx.ProgressDialog("Movie processing", "Movie is being written...",
                           maximum = self.engine.endProcessingFrame,self.engine.startProcessingFrame,
                           parent=self,
                           style = wx.PD_APP_MODAL | wx.PD_ELAPSED_TIME | wx.PD_SMOOTH | wx.PD_CAN_ABORT)
state = self.engine.processMovie()
f = state.next()
while f != None:
    c, s = dlg.Update(f, "Processing frame %d"%f)
    if not c:break
    f = state.next()
dlg.Destroy()

效果很好,绝对没有明显的速度损失,但是如果我不想的话,我希望能够调用 processMovie() 函数而不必处理生成器。

例如,我使用引擎模块的控制台脚本不关心进度,我可以使用它,但它注定要在没有显示的环境中执行,所以我真的不关心进度......

有人有我想出的另一种设计吗?(使用线程、全局变量、进程等)

我认为必须有一个设计可以干净地完成这项工作:-)

4

3 回答 3

2

使用生成器对此很好,但使用生成器的全部意义在于您可以内置语法:

for f in self.engine.processMovie():
    c, s = dlg.Update(f, "Processing frame %d"%f)
    if not c: break

如果你不关心这个,那么你可以说:

for f in self.engine.processMovie(): pass

或公开一个函数(例如engine.processMovieFull)来为您执行此操作。

你也可以使用一个普通的回调:

def update_state(f):
    c, s = dlg.Update(f, "Processing frame %d"%f)
    return c
self.engine.processMovie(progress=update_state)

...但是,如果您想零碎地处理数据,那就没那么好了;回调模型更喜欢一次完成所有工作——这就是生成器的真正好处。

于 2009-07-31T07:09:38.010 回答
1

这听起来像是事件的完美案例。该过程发送一个“状态更新事件”,任何想知道的人(在本例中为对话框)都会监听该事件。

于 2009-07-31T09:02:56.503 回答
0

首先,如果使用生成器,不妨将其用作迭代器:

state = self.engine.processMovie()

for f in state:
    c, s = dlg.Update(f, "Processing frame %d"%f)
    if not c:
        break

dlg.Destroy()

不要屈服None;完成后停止让步并离开该功能;或者提高StopIteration。这是结束生成的正确方法(并且在使用for循环时,这是必要的)。

除此之外,我喜欢这个主意。在我看来,这是对生成器的非常有效的使用。

您可能希望使可33配置(即可processMovie作为参数传递);33 似乎是一个随意的选择,如果你处理一部两小时的电影,我猜没有必要每 33 帧更新一次进度条。

于 2009-07-31T07:11:52.437 回答