Alternative a Long Loops [closed]

-1

Faccio parte di un team di software che sta scrivendo un'applicazione per console (senza interfaccia utente) in C #. La mia parte nel team è scrivere codice per chiamare le API RESTful da un sito di terze parti, elaborare i dati restituiti e salvarli nel database locale.

L'API di terze parti ha un limite sul numero di elementi restituiti in una singola chiamata (massimo 100 elementi) che mi richiede di chiamare la stessa API più volte su un ciclo per recuperare tutti i dati che spesso vengono eseguiti in molte migliaia di record . Una volta recuperato un singolo record, ho bisogno di effettuare più chiamate API per ottenere ulteriori dettagli del record che viene recuperato, che richiede di nuovo cicli multipli a causa del limite massimo imposto dall'API di terze parti.

Tutto sommato il processo ha finito per essere molti livelli di loop annidati! Non riesco a pensare ad un modo migliore di gestire questo processo senza tanti cicli annidati. Ho pensato di usare espressioni stile lambda per enumerare gli oggetti ma ho letto da qualche parte che le espressioni lambda sono zucchero sintattico sui loop! Qualche idea che possa migliorare il codice senza utilizzare cicli annidati lunghi e dolorosi?

    
posta Xami Yen 09.10.2018 - 19:49
fonte

4 risposte

5

I loop non sono necessariamente cattivi. Un sacco di grandi caratteristiche diverse dalle espressioni Lambda si accumulano probabilmente in loop. Una delle grandi cose dei computer è che è facile indurli a ripetere lo stesso insieme di istruzioni tutte le volte che è necessario, sia che si tratti di loop per loop, ricorsione, espressioni lambda, ecc.

Ciò che probabilmente non vuoi fare è avere una serie di loop nidificati complicati con la stessa funzione. Fai in modo che ogni API chiami la propria funzione e abbia le funzioni per gestire la creazione dei dati che stai ricevendo, e il codice non dovrebbe essere troppo brutto dato che ti interessano solo alcuni loop particolari in ogni punto del processo.

Neanche io avrei paura di Lambdas. Molte volte sono più eleganti dei loop e se ti trovi bene con loro dovresti usarli. Soprattutto in un linguaggio come C # in cui sono potenti e popolari.

Ora se il problema è che stai facendo troppe chiamate API che impiegano troppo tempo o ottieni un numero limitato di chiamate API, allora non è un problema con i loop ma con l'architettura di ottenere i tuoi dati.

    
risposta data 09.10.2018 - 20:09
fonte
1

Il problema, a quanto ho capito: si dispone di un'API che implementa il paging (un limite al numero di elementi in una risposta), tipico per evitare problemi di prestazioni su client e server. Per eseguire il loop su tutti gli elementi, è necessario un ciclo per ogni risposta e un ciclo per chiamare ripetutamente l'API. In poche parole, hai due loop in cui vuoi uno.

Soluzione: crea un metodo che restituisce un iteratore. In C # puoi usare yield per questo che semplifica enormemente le cose. Non codifico molto C # ma pythonesque psuedocode sarebbe simile a questo:

foo_items(params...):
  do:
    list items = call_api(params)
    for item in items:
      yield item
  while items != None

Ora puoi semplicemente scorrere l'intero iteratore nella parte principale della tua logica e nascondere il doppio loop dalla vista.

    
risposta data 10.10.2018 - 16:22
fonte
0

È difficile dire quale sia esattamente la soluzione ideale per la situazione che stai descrivendo perché non conosco tutti i vincoli. Ma generalmente il modo in cui evito i cicli annidati come quello che stai descrivendo è di evitare di provare a fare tutto in una volta e invece di suddividere le cose in una struttura più a più livelli. Il risultato finale è una serie di loop di medie dimensioni piuttosto che un loop grande con molti loop più piccoli al suo interno.

Ad esempio, supponiamo che al momento tu abbia un ciclo principale che trova tutti gli ID account per gli account che stai cercando e un ciclo annidato che trova tutti gli ID evento per ogni account così come li trovi. Invece, si farebbe il primo ciclo solo ottenere tutti gli ID account e raccogliere gli ID in un elenco. Quindi, una volta ottenuti tutti gli ID, creare un altro ciclo per controllare ciascun account nell'elenco per gli ID evento. Puoi ripetere questo per cose sempre più specifiche. Se le chiamate API sono abbastanza simili, è probabile che tu possa condividere la maggior parte del codice effettivo per chiamare l'API più volte e passare attraverso gli elementi, in modo che ogni passo "loop" sia solo una chiamata a API.GetAllRecords (type="Account ") o qualsiasi altra cosa. Solitamente più parti le cose in passaggi separati che non interagiscono direttamente tra loro, più pulito puoi creare il tuo codice.

    
risposta data 09.10.2018 - 20:25
fonte
0

Che ne pensi di rompere ogni loop nella sua funzione? Questo ti permette di incapsulare ogni livello di astrazione. Penso che il problema sia che (forse per motivi di prestazioni?) Vuoi evitare di scorrere tra più elenchi. Preferisci semplicemente mantenere i dati una volta che ce l'hai.

Tuttavia, ti esorto a evitarlo per 2 motivi: manutenibilità e leggibilità. Sembra che la tua funzione stia facendo troppo raggiungendo l'API, elaborandola e salvandola nel database tutto nello stesso momento. Inoltre, suppongo che tu non abbia diviso il tuo codice in più livelli di astrazione. Ciò rende difficile per un nuovo programmatore iniziare a guardare il tuo codice e analizzare ciò che sta realmente accadendo.

Quello che consiglio è dividere la tua funzione. Inoltre, questo ti permette di vedere dove sono i colli di bottiglia. Quindi, se la performance non è dove vuoi che sia, puoi iniziare a rifattorizzare in qualcosa che gestisca i dati in modo più efficiente.

La tua funzione di primo livello sarebbe quindi:

 Service.run() : void
     fetchAllRecordsFromAPI() : RecordList
     fetchAllRecordDetailsFromAPI(RecordList) : RecordDetailsList
     saveAllRecordsToDatabase(RecordList) : void
     saveAllRecordDetailsToDatabase(RecordDetailsList) : void

Dovresti quindi implementare ciascuna di queste funzioni per gestire la sua funzione specifica assegnata. Ovviamente è pseudocodice e non è pulito come potrebbe essere, ma ottieni il punto.

    
risposta data 10.10.2018 - 18:55
fonte

Leggi altre domande sui tag