Architettura manutenibile per una serie di elaborazioni simultanee e seriali

0

Ho una matrice di valori che va da poche decine a poche centinaia di righe e colonne (sempre quadrate). Ho una serie di compiti che devono essere eseguiti sulla matrice. (Sto usando il Algoritmo ungherese .) Perché potrebbero richiedere molto tempo, sto facendo il lavoro su diversi thread per impedire all'interfaccia utente di rimanere bloccata. Ma sto scoprendo che l'asincronicità di esso rende il codice più difficile da seguire, e mi chiedo se c'è un modo migliore?

Lo sto facendo su macOS usando dispatch_queues . Funziona in questo modo:

  1. Per ogni riga, trova il valore minimo nella riga e sottrai da tutti gli elementi nella riga
  2. Per ogni colonna, fai lo stesso
  3. Per ciascuna riga, se ha un valore 0 singolo, contrassegnalo e elimina tutti gli 0 nella colonna corrispondente
  4. Altre cose a cui non sono ancora arrivato ...

Quindi per il passaggio 1, è possibile lavorare su più righe contemporaneamente, quindi utilizzo dispatch_async() per avviare l'elaborazione della riga. Il problema è che dal momento che avviene in modo asincrono, ho bisogno di un finalizzatore che inizi l'elaborazione delle colonne. Anche loro possono essere eseguiti contemporaneamente, quindi uso un altro dispatch_queue e avvialo tramite dispatch_async() . Ancora una volta, ho bisogno di un finalizzatore poiché sta accadendo in modo asincrono.

Quindi ora, invece di aver scritto una funzione abbastanza semplice come questa:

void processMatrix(Matrix m)
{
    processRows(m);
    processColumns(m);
    assignZeroes(m);
    // etc.
}

Ho una catena di funzioni che non sono ovviamente correlate e contengono un codice estraneo di manutenzione:

void processMatrix(Matrix m)
{
    dispatch_queue_t rowQueue = dispatch_queue_create(...);
    dispatch_queue_setContext(rowQueue, contextData);
    dispatch_queue_setFinalizer(rowQueue, doneProcessingRows);
    dispatch_async(rowQueue, ^{ processRows(m); });
}

void doneProcessingRows(void* context)
{
    dispatch_queue_t colQueue = dispatch_queue_create(...);
    dispatch_queue_setContext(colQueue, contextData);
    dispatch_queue_setFinalizer(colQueue, doneProcessingColumns);
    dispatch_async(colQueue, ^{ processColumns(m); });
}

void doneProcessingColumns(void* context)
{
    dispatch_queue_t assignmentQueue = dispatch_queue_create(...);
    dispatch_queue_setContext(assignmentQueue, contextData);
    dispatch_queue_setFinalizer(assignmentQueue, doneAssigning);
    dispatch_async(assignmentQueue, ^{ processAssignments(m); });
}

Quello che mi chiedo è se c'è un modo migliore per scrivere questo codice, quindi è più facile leggere e capire e vedere il flusso di elaborazione? Mi piacerebbe mantenerlo il più concorrente possibile per motivi di prestazioni.

    
posta user1118321 04.04.2017 - 06:13
fonte

1 risposta

1

(Disclaimer: non ho familiarità con la programmazione Objective C, quindi potrebbero esserci errori nella mia risposta Alcune informazioni si basano su collegamenti online che potrebbero non essere aggiornati.

In generale, lo stile di codifica può essere conosciuto come Fork-Join o Bulk Synchronization.

Il tuo codice potrebbe essere solo alcuni passaggi di refactoring dallo stato perfetto:

  1. Potresti risolvere il problema della ripetizione del codice estraendone la parte comune in una funzione di supporto e specificando le parti che cambiano come argomenti della funzione? Per fare ciò, devi passare in blocchi come argomenti per quella funzione .

  2. Potresti rinominare le funzioni, in modo che invece di dire che ogni funzione viene chiamata quando viene fatto qualcos'altro, la chiamerai con l'attività che eseguirà quando viene chiamata? Ad esempio: startProcessingRows , startProcessingColumns e startProcessingAssignments . Questo aiuterà a capire meglio la funzione.

risposta data 04.04.2017 - 08:19
fonte

Leggi altre domande sui tag