Pergunta

Atualmente estou usando geradores como uma maneira rápida de obter o progresso de processos longos e estou me perguntando como isso é feito normalmente, pois não acho muito elegante...

Deixe-me explicar primeiro, eu tenho um módulo engine.py que faz algum processamento de vídeo (segmentação, subtração bg/fg, etc) que leva muito tempo (de segundos a vários minutos).

Eu uso este módulo a partir de uma GUI escrita em wxpython e um script de console.Quando observei como implementar caixas de diálogo de progresso no wxpython, vi que precisava obter de alguma forma um valor de progresso para atualizar minha caixa de diálogo, o que é pura lógica, você admite...Então decidi usar o número de quadros processados ​​em minhas funções de mecanismo, produzir o número do quadro atual a cada 33 quadros e produzir Nenhum quando o processamento for concluído.

fazendo isso, aqui está o que parece:

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()

Isso funciona muito bem, não há absolutamente nenhuma perda de velocidade perceptível, mas eu gostaria de poder chamar a função processMovie() sem ter que lidar com geradores, se não quiser.

Por exemplo, meu script de console que usa o módulo do mecanismo não se importa com o progresso, eu poderia usá-lo, mas está destinado a ser executado em um ambiente onde não há exibição, então realmente não me importo com o progresso...

Alguém com outro design que eu criei?(usando threads, globais, processos, etc)

Deve haver um design em algum lugar que faça esse trabalho de forma limpa, eu acho :-)

Foi útil?

Solução

Usar um gerador é bom para isso, mas o objetivo de usar geradores é para que você possa incorporar a sintaxe:

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

Se você não se importa com isso, você pode dizer:

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

ou expor uma função (por exemplo.engine.processMovieFull) para fazer isso por você.

Você também pode usar um retorno de chamada simples:

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

...mas isso não é tão bom se você deseja processar os dados aos poucos;os modelos de retorno de chamada preferem fazer todo o trabalho de uma vez – esse é o verdadeiro benefício dos geradores.

Outras dicas

Parece um caso perfeito para eventos.O processo envia um "evento de atualização de status" e qualquer pessoa que queira saber (neste caso, a caixa de diálogo) escuta esse evento.

Primeiro de tudo, se você usa um gerador, você também pode usá-lo como iterador:

state = self.engine.processMovie()

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

dlg.Destroy()

E não ceda None;pare de ceder quando terminar e saia da função;alternativamente aumentar StopIteration.Esta é a maneira correta de encerrar a geração (e ao usar um for loop, é necessário).

Fora isso, gosto da ideia.Na minha opinião, este é um uso muito válido de geradores.

Você pode querer fazer o 33 configurável (ou seja,aceitável para processMovie como parâmetro);33 parece uma escolha arbitrária, e se você processar um filme de duas horas, não há necessidade de atualizar a barra de progresso a cada 33 quadros, eu acho.

Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top