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:
- Per ogni riga, trova il valore minimo nella riga e sottrai da tutti gli elementi nella riga
- Per ogni colonna, fai lo stesso
- Per ciascuna riga, se ha un valore 0 singolo, contrassegnalo e elimina tutti gli 0 nella colonna corrispondente
- 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.