использование генераторов в качестве уведомителя о прогрессии

StackOverflow https://stackoverflow.com/questions/1211035

  •  06-07-2019
  •  | 
  •  

Вопрос

В настоящее время я использую генераторы как быстрый способ получения прогресса в длинных процессах, и мне интересно, как это обычно делается, так как я нахожу это не очень элегантным ...

Позвольте мне сначала объяснить, у меня есть модуль engine.py, который выполняет некоторую обработку видео (сегментацию, вычитание bg / fg и т. д.), которая занимает много времени (от секунд до нескольких минут).

Я использую этот модуль из графического интерфейса, написанного на wxpython и консольного скрипта. Когда я посмотрел, как реализовать диалоги прогресса в 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 () без необходимости работать с генераторами, если я этого не хочу.

Например, мой консольный скрипт, который использует модуль движка, не заботится о прогрессе, я мог бы использовать его, но он предназначен для выполнения в среде, где нет отображения, так что я действительно не беспокоюсь о прогрессе ...

Кто-нибудь с другим дизайном, который я придумал? (используя потоки, глобалы, процессы и т. д.)

Где-то должен быть дизайн, который делает эту работу чистой, я думаю: -)

Это было полезно?

Решение

Использование генератора прекрасно для этого, но весь смысл использования генераторов заключается в том, что вы можете встроить синтаксис:

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)

... но это не так хорошо, если вы хотите обрабатывать данные по частям; Модели обратного вызова предпочитают выполнять всю работу одновременно - это реальная выгода генераторов.

Другие советы

Это звучит как идеальный случай для событий. Процесс отправляет «событие обновления статуса», и любой, кто хочет знать (в данном случае это диалог), слушает это событие.

Прежде всего, если вы используете генератор, вы можете использовать его как итератор:

state = self.engine.processMovie()

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

dlg.Destroy()

И не поддавайтесь Нет ; прекратите уступать, когда закончите, и выйдите из функции; альтернативно поднять StopIteration . Это правильный способ завершения генерации (и при использовании цикла for это необходимо).

Кроме этого, мне нравится идея. На мой взгляд, это очень правильное использование генераторов.

Возможно, вы захотите сделать 33 настраиваемым (то есть передаваться в processMovie в качестве параметра); 33 выглядит как произвольный выбор, и если вы обрабатываете двухчасовой фильм, мне не нужно обновлять индикатор выполнения каждые 33 кадра.

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top