Pergunta

Mantendo a GUI responsiva enquanto o aplicativo faz algum processamento de CPU-pesado é um dos desafios da programação GUI eficaz.

Aqui está uma boa discussão sobre como fazer isso em wxPython. Para resumir, há 3 maneiras:

  1. Use tópicos
  2. Use wxYield
  3. Chunk o trabalho e fazê-lo no manipulador de eventos IDLE

Qual o método têm você encontrado para ser o mais eficaz? Técnicas de outras estruturas (como Qt, GTK ou Windows API) também são bem vindos.

Foi útil?

Solução

Threads. Eles são o que eu sempre ir para porque você pode fazê-lo em cada quadro que você precisa.

E uma vez que você está acostumado a multi-threading e processamento paralelo em um idioma / quadro, você é bom em todos os frameworks.

Outras dicas

Definitivamente threads. Por quê? O futuro é multi-core. Quase qualquer nova CPU tem mais de um núcleo ou se tem apenas um, pode apoiar hyperthreading e, portanto, fingir que tem mais de um. Para efetivamente fazer uso de CPUs multi-core (e Intel está planejando ir até 32 núcleos em um futuro não tão distante), você precisa de vários segmentos. Se você executar tudo em um segmento principal (geralmente o segmento interface do usuário é o fio principal), os usuários terão CPUs com 8, 16 e um dia 32 núcleos e sua aplicação nunca usa mais de um destes, IOW corre muito, muito mais lento do que poderia ser executado.

real se você planeja uma aplicação hoje em dia, eu iria embora do design clássico e pensar em uma relação mestre / escravo. Sua interface é o mestre, é só tarefa é interagir com o usuário. Que está exibindo dados para o usuário e coleta de entrada do usuário. Sempre que você aplicativo precisa "processar todos os dados" (mesmo em pequenas quantidades e muito mais importantes grandes), criar uma "tarefa" de qualquer espécie, para a frente essa tarefa para uma discussão de fundo e fazer o fio executar a tarefa, fornecendo feedback para o UI (por exemplo, quantos por cento que tenha concluído ou apenas se a tarefa ainda está em execução ou não, então a interface do usuário pode mostrar um "indicador de work-in-progress"). Se possível, dividir a tarefa em muitos pequenos, sub-tarefas independentes e executar mais de um processo de fundo, alimentando uma sub-tarefa para cada um deles. Dessa forma, sua aplicação pode realmente beneficiar de multi-core e chegar mais rápido quanto mais núcleos CPUs ter.

Na verdade, empresas como a Apple e Microsoft já estão planejando em como fazer as suas ainda mais simples UIs rosca-se de vários segmentos. Mesmo com a abordagem acima, você pode um dia ter a situação que a interface do usuário é o próprio gargalo. Os processos em segundo plano pode processar dados muito mais rápido que a interface do usuário pode apresentá-lo ao usuário ou pedir ao utilizador para a entrada. Hoje, muitos frameworks de UI são pouco thread-safe, muitos não thread-safe em tudo, mas isso vai mudar. processamento serial (fazendo uma tarefa após a outra) é um projeto morrendo, processamento paralelo (fazer muitas tarefas ao mesmo tempo) é onde o futuro vai. Basta olhar para os adaptadores gráficos. Mesmo o cartão NVidia mais moderna tem um desempenho lamentável, se você olhar para a velocidade de processamento em MHz / GHz apenas do GPU. Como vem ele pode bater o crap fora de CPUs quando se trata de cálculos 3D? Simples: Em vez de calcular um ponto polígono ou um pixel textura após o outro, ele calcula muitos deles em paralelo (na verdade, um monte ao mesmo tempo) e de que maneira ela atinge um rendimento que ainda faz CPUs grito. Por exemplo. a ATI X1900 (para citar o concorrente também) tem 48 unidades de sombreamento!

Eu acho delayedresult é o que você está procurando:

http://www.wxpython.org/docs /api/wx.lib.delayedresult-module.html

Veja a demo wxpython para um exemplo.

Threads ou processos, dependendo da aplicação. Às vezes é realmente melhor ter o GUI seja do próprio programa e basta enviar chamadas assíncronas para outros programas quando tem trabalho a fazer. Você ainda vai acabar tendo vários segmentos do GUI para monitorar resultados, mas pode simplificar as coisas, se o trabalho que está sendo feito é complexo e não diretamente ligado à GUI.

Tópicos - Vamos usar uma visão simples de 2 camadas (GUI, lógica da aplicação).

O trabalho lógica de aplicação deve ser feita em um segmento de Python separado. Para eventos assíncronos que precisam propagar-se para a camada de GUI, sistema de eventos uso de wx para eventos personalizados correios. Publicação de eventos wx é o segmento de seguros para que você pode conseguir fazê-lo a partir de vários contextos.

Trabalho em outra direção (eventos de entrada GUI provocando lógica da aplicação), eu descobri que é melhor para a casa-roll um sistema de evento personalizado. Use o módulo da fila para ter uma forma thread-safe de empurrar e popping objetos de evento. Em seguida, para cada membro função síncrona, emparelhá-lo com uma versão assíncrona que empurra o objeto de função de sincronização e os parâmetros para a fila de evento.

Isso funciona particularmente bem se apenas uma única operação de nível de lógica de aplicação pode ser executada por vez. A vantagem deste modelo é que a sincronização é simples - cada função síncrona funciona dentro de seu próprio contexto sequencialmente do início ao fim sem se preocupar de preferência ou produzindo mão-codificado. Você não vai precisar de bloqueios para proteger suas seções críticas. No final da função, coloca um evento para a camada de interface gráfica indicando que a operação está completa.

Você poderia escalar isso para permitir a existência de múltiplas threads em nível de aplicativo, mas as preocupações habituais com sincronização irá voltar a aparecer.

editar - Esqueceu-se de mencionar a beleza desta é que é possível completamente desacoplar a lógica da aplicação do código de GUI. A modularidade ajuda se você decidir usar um quadro diferente ou uso fornecer uma versão de linha de comando do aplicativo. Para fazer isso, você precisará de um despachante evento intermediário (nível de aplicação -> GUI) que é implementado pela camada de GUI.

Trabalho com o Qt / C ++ para Win32.

Dividimos as principais unidades de trabalho em diferentes processos. A GUI é executado como um processo separado e é capaz de comando / receber dados a partir dos processos de "trabalhador", conforme necessário. Funciona bem no mundo de hoje multi-core.

Esta resposta não se aplica à pergunta do OP sobre Python, mas é mais de uma meta-resposta.

A maneira mais fácil é threads. No entanto, nem todas as plataformas tem rosqueamento preventiva (por exemplo BREW, alguns outros sistemas embarcados) Se, eventualmente, simplesmente pedaço do trabalho e fazê-lo no manipulador de eventos IDLE.

Outro problema com o uso de threads em BREW é que ele não limpar C ++ objetos pilha, por isso é muito fácil de vazamento de memória se você simplesmente matar o segmento.

Eu uso tópicos tão principal evento de loop do GUI nunca bloqueia.

Para alguns tipos de operações, usando processos separados faz muito sentido. De volta ao dia, gerando um processo incorridos muita sobrecarga. Com hardware moderno essa sobrecarga é nem sequer um pontinho na tela. Isto é especialmente verdadeiro se você está gerando um processo de longa duração.

One (discutível) vantagem é que ele é um modelo conceitual simples do que tópicos que podem levar a um código mais sustentável. Ele também pode fazer seu código mais fácil de teste, como você pode escrever scripts de teste que exercem esses processos externos sem a necessidade de envolver o GUI. Alguns podem até argumentar que é a principal vantagem.

No caso de algum código que eu já trabalhou em, a mudança de tópicos para processos separados levaram a uma redução líquida de mais de 5000 linhas de código, enquanto ao mesmo tempo fazendo a interface gráfica mais ágil, o código mais fácil de manter e testar, tudo ao mesmo tempo melhorar o desempenho global total.

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