Progettazione per un algoritmo che segnala i progressi

5

Ho un algoritmo iterativo e voglio stampare i progressi. Tuttavia, potrei anche volere che non stampi qualsiasi informazione, o stamparla in altro modo, o fare altra logica. In un linguaggio orientato agli oggetti, eseguirò le seguenti soluzioni:

Soluzione 1: metodo virtuale

avere la classe dell'algoritmo MyAlgoClass che implementa l'algo. La classe implementa anche un metodo di reportIteration virtuale (iterInfo) che è vuoto e può essere reimplementato. Sottoclassi MyAlgoClass e sovrascrivi reportIteration in modo che faccia ciò che deve fare. Questa soluzione consente di portare ulteriori informazioni (ad esempio, l'unità di file) nella classe reimplementata.

Non mi piace questo metodo perché raggruppa due funzionalità che potrebbero non essere correlate, ma nelle app GUI potrebbe essere ok.

Soluzione 2: schema osservatore

la classe dell'algoritmo ha un metodo di registro (Observer), mantiene una lista degli osservatori registrati e si occupa di chiamare notify () su ciascuno di essi. Observer :: notify () ha bisogno di un modo per ottenere le informazioni dal Soggetto, quindi ha due parametri, uno con il Soggetto e l'altro con i dati che il Soggetto può superare, o solo il Soggetto e l'Osservatore è ora in carica di interrogarlo per recuperare le informazioni pertinenti.

Soluzione 3: callback

Tendo a vedere il metodo di callback come un osservatore leggero. Invece di passare un oggetto, si passa un callback, che può essere una funzione semplice, ma anche un metodo di istanza in quei linguaggi che lo consentono (ad esempio, in python è possibile perché passare un metodo di istanza rimarrà legato all'istanza). C ++ tuttavia non lo consente, perché se si passa un puntatore a un metodo di istanza, this non verrà definito. Per favore correggimi a riguardo, il mio C ++ è piuttosto vecchio.

Il problema con i callback è che generalmente devi passarli insieme ai dati con cui vuoi richiamare il callback. Le callback non memorizzano lo stato, quindi devi passare sia la callback che lo stato a Subject per trovarlo durante l'esecuzione del callback, insieme a eventuali dati aggiuntivi che Subject può fornire sull'evento che sta segnalando.

Domanda

La mia domanda è relativa al fatto che ho bisogno di implementare il problema di apertura in un linguaggio che non è orientato agli oggetti, ovvero Fortran 95, e sto combattendo con il mio solito ragionamento basato su ipotesi e stile di Python. Penso che in Fortran il concetto sia simile a C, con il guaio aggiuntivo che in C puoi memorizzare un puntatore a funzione, mentre in Fortran 95 puoi solo passarlo in giro.

Hai commenti, suggerimenti, suggerimenti e stranezze a riguardo (in C, C ++, Fortran e python, ma anche in qualsiasi altra lingua, così da avere un confronto tra le caratteristiche linguistiche che possono essere sfruttate a questo proposito ) su come progettare un algoritmo che deve riportare l'avanzamento su qualche entità esterna, usando lo stato sia dall'algoritmo che dall'entità esterna?

    
posta Stefano Borini 18.02.2011 - 14:08
fonte

6 risposte

5

Hai considerato un modello di "pompa"? Esternalizzare l'iterazione effettiva e memorizzare lo stato completo richiesto per riprendere l'iterazione all'interno delle variabili / struttura che esegue il calcolo. Quindi, ogni iterazione, leggi una sorta di variabile di stato di avanzamento che viene scritta dall'algoritmo.

Mi sembra che, a causa del linguaggio primitivo con cui sei bloccato, sei limitato ad alcuni semplici approcci che non sono ideali.

    
risposta data 18.02.2011 - 14:37
fonte
2

Per aggiungere un aspetto C ++ a questo, il C ++ moderno ha diverse soluzioni al # 3. È possibile associare praticamente qualsiasi entità callable compatibile (che si tratti di una funzione, un oggetto funzione o una funzione membro) utilizzando std::bind , utilizzare std::function per lo stesso compito o utilizzare una funzione lambda.

Tutte e tre le possibilità sono supportate dal prossimo standard C ++ (che dovrebbe essere rilasciato quest'anno). Le due soluzioni di libreria sono già fornite da quasi tutti i compilatori (anche se potrebbero essere nello spazio dei nomi std::tr1 , piuttosto che std ), e se non possono essere usate come parte delle librerie boost fenomenali (quindi nello spazio dei nomi boost ). Le funzioni Lambda sono implementate dalle recenti versioni VC e GCC.

Penso che il modo più semplice per farlo sarebbe quello di rendere il parametro callback un argomento modello o std::function<void(progress_info_t)> .

    
risposta data 18.02.2011 - 23:25
fonte
0

Stai facendo un processo iterativo le cui proprietà di convergenza non sono facilmente prevedibili, ma che desideri continuare fino a quando non converge, o se ne deduce in profondità doo-doo? Se non "stampa" informazioni sul suo progresso (numero di iterazioni, un residuo (o qualsiasi altra figura di progresso ha senso), allora l'utente potrebbe essere preoccupato, "è nei guai? Potrebbe essere appeso, o essere in un ciclo infinito? ". Quindi una cosa sarebbe memorizzare queste proprietà in un indirizzo (o file esterno) che può essere letto da qualche processo di monitoraggio o la tua preoccupazione è molto diversa da questa?

    
risposta data 19.02.2011 - 00:03
fonte
0

Passa il riferimento alla tua funzione di callback come parametro aggiuntivo nel tuo algoritmo.

Se non vuoi preoccuparti dei richiami di questa chiamata, passa una semplice funzione di stub che non fa altro che restituire.

    
risposta data 16.09.2011 - 00:11
fonte
0

A seconda della natura del prodotto, ho conosciuto più di un paio di sviluppatori che hanno appena messo una barra di avanzamento scorrevole che va avanti ogni secondo o due (qualche percento per tick), che non ha nulla a che vedere col progresso effettivo. C'è una callback alla fine per farla lampeggiare al 100% (o meno). È un trucco totale, ma di nuovo una barra di avanzamento è solo uno strumento per dire all'utente "per favore aspetta, sì il programma non si è rotto ed effettivamente sta facendo qualcosa".

Se stai parlando di una notifica di avanzamento dell'installazione complicata, non è una buona idea, ma per qualcosa che potrebbe richiedere 30 secondi o meno va bene.

In altre parole, se si tratta di una piccola operazione, non preoccuparti di essere super preciso, o addirittura rappresentativo, nel tuo resoconto dei progressi.

    
risposta data 16.09.2011 - 02:59
fonte
-1

Poiché non c'è una risposta accettata, lancio una possibile soluzione. Hai provato un disegno in cui i valori sono osservabili al posto dell'algoritmo?

In c ++ avrei fatto qualcosa di simile a questo:

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 poi nel mio 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());
}
    
risposta data 30.09.2017 - 12:53
fonte

Leggi altre domande sui tag