Ottieni dati di servizio di iterazioni future

3

Ho un dubbio con il threading delle chiamate di servizio dati all'interno di un ciclo foreach. Ecco qui:

Supponiamo che tu debba richiedere i dati da un servizio e quindi elaborare tali dati, per questo esempio, supponiamo che la richiesta di dati impieghi 2 secondi e che l'elaborazione dei dati ne richieda un'altra. Se dovessi elaborare un elenco di 10000 elementi, come faresti?

La cosa che ho provato è stata:

Dictionary<int,Task<DataResponse>> d_tasks = Dictionary<int,Task<DataResponse>>();
for(int i=0;i<listOfElements;i++)
{
    if(i=0)
       //create and run task for first element, save it for latter use in d_tasks
    if(not last item)
       //create and run task for next element, save it for latter use in d_tasks
    if(i>0)
       //clean task data from previous element (clean d_tasks)

    d_tasks[listOfElements[i].Wait();
    DoWorkWithData(d_tasks[listOfElements[i].Result);
}

in questo modo sono stato in grado di ridurre il tempo nel ciclo, poiché ero in grado di utilizzare la latenza dal servizio per elaborare i dati.

Quindi ecco l'ultima domanda, è ok? sto dimenticando qualcosa? c'è qualche tipo di schema per questo tipo di situazioni?

Qualsiasi aiuto è apprezzato.

    
posta barclow 21.10.2016 - 02:39
fonte

2 risposte

2

Non sono sicuro di aver capito il tuo design. Sembra che tu sia Wait ing per ogni compito subito dopo averlo avviato. Penserei che avresti due loop (uno per creare e avviare i compiti, un altro per tornare sui risultati e elaborarli). Il tuo approccio a loop singolo aumenta davvero il parallelismo?

Ecco un altro modo per farlo sfruttando il novello Parallel.For . La cosa bella qui è che non abbiamo bisogno di mantenere un elenco di attività o risultati. Il lock potrebbe non essere necessario, a seconda che DoWorkWithData sia sicuro per i thread. Immagino che il suo scopo sia quello di compilare i 10.000 risultati in una struttura dati comune, quindi probabilmente deve essere considerata una sezione critica.

var lockObject = new object();
Parallel.ForEach(listOfElements,
                 (element) => { 
                                  var result = DoExpensiveParallelWork(element);
                                  lock(lockObject) { DoWorkWithData(result);}
                              });
    
risposta data 08.02.2017 - 02:22
fonte
1

È possibile utilizzare l'approccio async-await per la richiesta di dati dal servizio e paralleli per l'elaborazione dei dati.

Crea un metodo asincrono che invierà una richiesta al servizio e restituirà i risultati in modo asincrono

public async Task<DataResponse> LoadDataAsync(Element element)
{
    // await service.GetResponceAsync....
}

var loadTasks = listOfElements.Select(element => LoadDataAsync(element)).ToList();
var responses = await Task.WhenAll(loadTasks);

// Now you can process all data in parallel way
Parallel.ForEach(response => ProcessResponse(response));

La riga listOfElements.Select(element => LoadDataAsync(element)).ToList() invierà le richieste senza aspettare la risposta, il che fa sì che il tempo di risposta per tutte le richieste sia vicino al tempo di risposta di una richiesta.

await Task.WhenAll(loadTasks); attenderà che tutte le risposte e i risultati vengano elaborati in parallelo.

Per una grande quantità di elementi è possibile ottimizzare questo approccio elaborando i dati immediatamente dopo l'arrivo della risposta. Ma poi l'elaborazione dei dati in parallelo può essere difficile.

    
risposta data 09.04.2017 - 06:00
fonte

Leggi altre domande sui tag