Projetando um algoritmo que relate o progresso

5

Eu tenho um algoritmo iterativo e quero imprimir o progresso. No entanto, eu também posso querer que não imprima qualquer informação, ou imprima de forma diferente, ou faça outra lógica. Em uma linguagem orientada a objetos, eu executaria as seguintes soluções:

Solução 1: método virtual

tem a classe de algoritmo MyAlgoClass que implementa o algoritmo. A classe também implementa um método virtual reportIteration (iterInfo) que está vazio e pode ser reimplementado. Subclasse o MyAlgoClass e substitua reportIteration para que ele faça o que precisa fazer. Essa solução permite transportar informações adicionais (por exemplo, a unidade de arquivo) na classe reimplementada.

Eu não gosto desse método porque ele agrupa duas funcionalidades que podem não estar relacionadas, mas em aplicativos GUI pode estar tudo bem.

Solução 2: padrão de observação

a classe do algoritmo tem um método de registro (Observer), mantém uma lista dos observadores registrados e cuida da chamada notify () em cada um deles. Observer :: notify () precisa de uma maneira de obter as informações do Sujeito, então ele tem dois parâmetros, um com o Sujeito e outro com os dados que o Sujeito pode passar, ou apenas o Sujeito e o Observador estão agora no comando. de consultá-lo para buscar as informações relevantes.

Solução 3: retornos de chamada

Eu costumo ver o método de retorno de chamada como um observador leve. Em vez de passar um objeto, você passa um retorno de chamada, que pode ser uma função simples, mas também um método de instância nos idiomas que o permitem (por exemplo, em python porque passar um método de instância permanecerá vinculado à instância). No entanto, o C ++ não permite, porque se você passar um ponteiro para um método de instância, this não será definido. Por favor, corrija-me a esse respeito, meu C ++ é bem antigo.

O problema com retornos de chamada é que geralmente você tem que passá-los junto com os dados que você deseja que o retorno de chamada seja invocado. Os retornos de chamada não armazenam o estado, portanto, é necessário passar o retorno de chamada e o estado para o Subject para encontrá-lo na execução do retorno de chamada, juntamente com todos os dados adicionais que o Subject fornecer sobre o evento. / p>

Pergunta

Minha pergunta é relativa ao fato de que eu preciso implementar o problema de abertura em uma linguagem que não é orientada a objetos, a saber Fortran 95, e estou lutando com meu raciocínio usual que é baseado em suposições e estilo python. Eu acho que em Fortran o conceito é similar ao C, com o problema adicional que em C você pode armazenar um ponteiro de função, enquanto no Fortran 95 você pode apenas passá-lo.

Você tem algum comentário, sugestão, dicas e peculiaridades a esse respeito (em C, C ++, Fortran e python, mas também em qualquer outro idioma, para ter uma comparação dos recursos de linguagem que podem ser explorados a esse respeito? ) sobre como projetar um algoritmo que deve relatar o progresso para alguma entidade externa, usando o estado do algoritmo e da entidade externa?

    
por Stefano Borini 18.02.2011 / 14:08
fonte

6 respostas

5

Você já considerou um padrão de "bomba"? Externalize a iteração atual e armazene o estado completo necessário para retomar a iteração dentro das variáveis / estruturas que executam o cálculo. Então, apenas, em cada iteração, leia algum tipo de variável de estado de progresso que seja gravada pelo algoritmo.

Parece-me que, devido à linguagem primitiva em que você está preso, você está limitado a algumas abordagens simples que não são ideais.

    
por 18.02.2011 / 14:37
fonte
2

Para adicionar um aspecto de C ++ a isso, o C ++ moderno tem várias soluções para o # 3. Você pode vincular praticamente qualquer entidade que possa ser chamada (seja uma função, um objeto de função ou uma função de membro) compatível usando std::bind , use std::function para a mesma tarefa ou use uma função lambda.

Todas as três possibilidades são suportadas pelo próximo padrão C ++ (esperado para ser lançado este ano). As duas soluções de biblioteca já são fornecidas por quase todos os compiladores (embora possam estar no namespace std::tr1 , em vez de std ), e se não puderem ser usadas como parte das bibliotecas fenomenais de reforço (então no namespace boost ). As funções Lambda são implementadas por versões recentes de VC e GCC.

Acho que a maneira mais fácil de usar isso seria fazer com que o parâmetro de retorno de chamada digite um argumento de modelo ou std::function<void(progress_info_t)> .

    
por 18.02.2011 / 23:25
fonte
0

Você está fazendo um processo iterativo cujas propriedades de convergência não são facilmente previsíveis, mas que você deseja continuar até que converge, ou descobre que está em profunda doo-doo? Se ele não "imprime" informações sobre seu progresso (número de iterações, um resíduo (ou qualquer que seja o número de progresso que faça sentido), então o usuário pode ficar preocupado ", está em apuros? Poderia ser pendurado ou estar em um loop infinito? ". Então, uma coisa seria armazenar essas propriedades em um endereço (ou arquivo externo) que pode ser lido por algum processo de monitoramento. Ou a sua preocupação é bem diferente disso?

    
por 19.02.2011 / 00:03
fonte
0

Passe a referência à sua função de retorno de chamada como um parâmetro adicional para o seu algoritmo.

Se você não quer incomodar com os callbacks desta invocação, passe uma simples função stub que não faz nada mais do que retornar.

    
por 16.09.2011 / 00:11
fonte
0

Dependendo da natureza do produto, conheço mais do que alguns desenvolvedores que acabaram de colocar uma barra de progresso deslizante que vai a cada segundo ou dois (poucos por cento por escala), o que não tem nenhuma relação com o progresso real. Há um retorno de chamada no final para torná-lo flash para 100% (ou não). É um hack total, mas, novamente, uma barra de progresso é apenas uma ferramenta para dizer ao usuário "por favor, espere, sim, o programa não quebrou e está realmente fazendo alguma coisa".

Se você está falando sobre uma grande e complicada notificação de progresso de instalação, isso não é uma boa ideia, mas para algo que pode levar 30 segundos ou menos, tudo bem.

Em outras palavras, se for uma operação pequena, não se preocupe em ser super preciso ou mesmo representativo em seus relatórios de progresso.

    
por 16.09.2011 / 02:59
fonte
-1

Como não há uma resposta aceita, eu tiro uma possível solução. Você já tentou um design em que os valores são observáveis em vez do algoritmo?

Em c ++ eu faria algo assim:

template <typename T>
struct observable
{
typedef function<void(const T&)> observer;

list<observer> observers;

T val;

void notify(const T& val)
{
    for(auto&& o : observers)
        o(val);
}

void operator=(const T& val)
{
    this->val = val;
    notify(this->val);
}

void watch(const observer& obs)
{
    observers.push_back(obs);
}

};

E depois no meu algo:

struct myalgo
{
observable<info> _info;

void do_work(params)
{
    info myinfo;
    do { job(); info.x = "info1" info.y = "info2"; _info = myinfo; }
    while (!has_to_stop());
}
    
por 30.09.2017 / 12:53
fonte