Às vezes, o usuário inicia uma operação técnica estendida que demora um pouco para ser executada. Nesses casos, geralmente é bom exibir algum tipo de barra de progresso, juntamente com informações sobre qual tarefa está sendo executada no momento.
Para evitar o acoplamento próximo entre a interface do usuário e as camadas lógicas, geralmente é melhor que a comunicação ocorra por meio de algum tipo de proxy. Ou seja, o back-end não deve manipular seus próprios elementos de interface do usuário nem interagir diretamente com a camada intermediária.
Obviamente, deve haver algum retorno de chamada em algum lugar para que isso funcione. Geralmente, eu o implementei de duas maneiras:
Passe um objeto mutável para o back-end e faça com que o back-end faça alterações no andamento. O objeto notifica o front-end quando ocorre uma alteração.
Passe uma função de retorno de chamada no formulário
void f(ProgressObject)
ouProgressObject -> unit
que o back-end chama. Nesse caso, o back-end constrói oProgressObject
e é completamente passivo. Ele deve construir um novo objeto toda vez que desejar relatar progresso, presumo.
Quais são as desvantagens e vantagens desses métodos? Existe um melhor método acordado para usar? Existem circunstâncias diferentes para o seu uso?
Existem técnicas completamente diferentes de relatar o progresso que eu negligenciei?
fonte
BackgroundWorker
esse RH menciona. Embrulhado em uma classe personalizada, juntamente com um "formulário de progresso" etc., e um mecanismo simples para comunicar uma exceção - conforme oBackgroundWorker
design é executado em um encadeamento separado. Na medida em que usamos seus recursos da maneira sugerida pelo .Net, isso pode ser considerado idiomático. E em qualquer contexto de linguagem / estrutura, "idiomático" pode ser o melhor.Respostas:
É difícil equilibrar a eficiência se o back-end notificar a esse respeito. Sem cuidado, você pode descobrir que incrementar seu progresso acaba dobrando ou triplicando o tempo necessário para concluir a operação, se você estiver buscando uma atualização de progresso muito suave.
Eu não entendo muito a diferença aqui.
Faça uma pesquisa a partir do front-end em um thread separado com incrementos atômicos no back-end. A pesquisa faz sentido aqui, pois é para uma operação que termina em um período finito e a probabilidade de o front-end pegar mudanças de estado é alta, especialmente se você está buscando uma barra de progresso suave e sedosa. Você pode considerar variáveis de condição se não gostar da idéia de pesquisar a partir do encadeamento de front-end, mas nesse caso, convém evitar notificar cada incremento de barra de progresso granular.
fonte
Essa é a diferença entre um mecanismo de notificação push e pull .
O objeto mutável (o pull ) precisará ser pesquisado repetidamente pela interface do usuário e sincronizado se você espera que a tarefa de back-end seja executada em um thread de segundo plano / trabalhador.
O retorno de chamada ( push ) só criará trabalho para a interface do usuário quando algo realmente mudar. Muitas estruturas de interface do usuário também têm um invokeOnUIThread chamado de um thread de trabalho para fazer com que um pedaço de código seja executado no thread da interface do usuário, para que você possa realmente fazer as alterações sem abordar os riscos relacionados ao thread. (trocadilho pretendido)
Em geral, as notificações por push são preferíveis porque só funcionam quando o trabalho precisa ser feito.
fonte
The mutable object (the pull) will need to be repeatably polled by the UI and synchronized if you expect the back-end task to be executed in a background/worker thread.
- Não se o objeto mutável for o próprio diálogo ou uma interface de trabalho para ele. Obviamente, isso equivale a um retorno de chamada.Estou usando websockets com AngularJS. Quando o front-end recebe uma mensagem, ele é exibido em uma área de mensagem designada que desaparece após alguns segundos. No back-end, eu apenas posto mensagens de status em uma fila de mensagens. Só envio texto, mas não há motivo para não enviar um objeto de status com valores como porcentagem concluída ou velocidade de transferência.
fonte
Você menciona seus "dois caminhos" como se fossem conceitos separados, mas quero insistir um pouco nisso.
Você já disse que deseja evitar o acoplamento próximo da interface do usuário e da lógica, para que eu possa assumir com segurança que esse "objeto mutável" que você está passando é na verdade uma implementação de uma interface específica definida no módulo lógico. Como tal, essa é apenas outra maneira de transmitir um retorno de chamada para o processo, que periodicamente é chamado com informações sobre o progresso.
Quanto aos benefícios e desvantagens ...
Uma desvantagem do método (1) é que a classe que implementa a interface pode fazê-lo apenas uma vez. (Se você deseja executar tarefas diferentes com chamadas diferentes, precisará de uma instrução switch ou do padrão de visitante.) Com o método (2), o mesmo objeto pode usar um retorno de chamada diferente para cada chamada do código de back-end sem a necessidade de um interruptor.
O ponto forte do método (1) é que é muito mais fácil ter vários métodos na interface do que lidar com os vários retornos de chamada do método (2) ou o retorno de chamada único com uma instrução switch para vários contextos.
fonte
As técnicas que você pode usar podem ser muito diferentes.
Eu tento descobrir com cenário diferente
Uma simples solicitação de login para o banco de dados (resposta média do banco de dados com um elemt) não precisa de um progresso no relatório, mas também pode disparar o thread da interface do usuário em tarefas separadas, por exemplo. assíncrono ou trabalhador em segundo plano, aqui você só precisa de um retorno de chamada para obter o resultado.
Mas e se você consultar para ver todo o seu inventário com o item 1mln? Essa consulta deve levar alguns minutos para ser concluída. Nesse caso, você precisa implementar o progresso do seu perport na lógica de negócios nos itens / itens do formulário, para atualizar sua interface do usuário e ter a opção de cancelar o retorno de chamada.
Mesmo caso para download de arquivo. Você sempre pode implementar aqui seu retorno de chamada de progresso no formato byte de bytes e manter todo o controle de comunicação sobre http é muito comum.
Na minha abordagem pessoal, implementei minha lógica de progresso de negócios apenas para meus clientes, evitando compartilhar outro objeto com o ponto final.
fonte