2015-07-29 4 views
9

Ho eseguito nuovamente un Task al termine. Di seguito la funzione che chiamo nello Application_Start della mia applicazione.Come eseguire più attività in C# e ottenere un evento al termine di queste attività?

private void Run() 
{ 
    Task t = new Task(() => new XyzServices().ProcessXyz()); 
    t.Start(); 
    t.ContinueWith((x) => 
    { 
     Thread.Sleep(ConfigReader.CronReRunTimeInSeconds); 
     Run(); 
    }); 
} 

voglio eseguire più compiti, numero che verrà letto da setttings web.config app.

sto cercando qualcosa di simile,

private void Run() 
{ 
    List<Task> tasks = new List<Task>(); 
    for (int i = 0; i < ConfigReader.ThreadCount - 1; i++) 
    { 
     tasks.Add(Task.Run(() => new XyzServices().ProcessXyz())); 
    } 

    Task.WhenAll(tasks); 

    Run(); 
} 

cosa è il modo corretto di fare questo?

+0

se non si vuole scavare nel costruire il proprio TaskRunner/estendere tale classe avrei probabilmente aspettare per il primo compito di porre fine utilizzando 'tasks.First(). Wait();' e quindi usa un ciclo while con Thread.Sleep per osservare lo stato delle attività rimanenti. –

+1

Si desidera eseguire ripetutamente un pezzo di codice in intervalli di tempo prestabiliti? Sembra proprio che esista il "Timer", davvero. E, naturalmente, se vuoi restare fedele a questo, legalo al risultato di 'Task.WhenAll' e tutto funzionerà come prima. – Luaan

+0

È necessario 'attendere Task.WhenAll (tasks);' o 'Task.WaitAll (tasks);'. Uno è una chiamata asincrona e dovrebbe essere atteso, l'altra è una funzione normale che può essere chiamata in un contesto sincrono. Ovviamente puoi anche usare il brutto 'Task.WhenAll (tasks) .Wait();' – Dorus

risposta

1

Se si desidera attendere tutte le attività alla fine e quindi riavviare loro, la risposta di Marco è corretta.

Ma se si vuole threadcount compiti da essere in esecuzione in qualsiasi momento (iniziare una nuova attività, non appena uno di essi finisce), quindi

void Run() 
{ 
    SemaphoreSlim sem = new SemaphoreSlim(ConfigReader.ThreadCount); 

    Task.Run(() => 
    { 
     while (true) 
     { 
      sem.Wait(); 
      Task.Run(() => { /*Your work*/ }) 
       .ContinueWith((t) => { sem.Release(); }); 
     } 
    }); 
} 
+0

Perché inner 'Task.Run'? Stai prendendo un blocco di thread mentre un altro viene utilizzato per eseguire qualcosa in modo sincrono. Basta usare 'sem.Wait(); prova {RunWhatever(); } finally {sem.Release(); } '. – Luaan

+0

@Luaan No Non è quello che voglio fare con il mio codice. Non sto aspettando un compito da finire, quindi ne avvio uno nuovo. Creo appena un nuovo compito ogni volta che finisce uno di questi. Quindi ci saranno sempre * attività ThreadCount * in esecuzione. – EZI

+0

Non ha Attività.WhenAll utilizza il ThreadPool che esegue automaticamente il numero "migliore" di attività contemporaneamente, mentre fa la coda agli altri? –

8

se si desidera eseguire i compiti uno dopo l'altro,

await Task.Run(() => new XyzServices().ProcessXyz()); 
await Task.Delay(ConfigReader.CronReRunTimeInSeconds * 1000); 

se si desidera eseguire loro in concomitanza, come i permessi Utilità di pianificazione,

await Task.WhenAll(new[] 
    { 
     Task.Run(() => new XyzServices().ProcessXyz()), 
     Task.Run(() => new XyzServices().ProcessXyz()) 
    }); 

Così, il metodo dovrebbe essere qualcosa di simile,

private async Task Run() 
{ 
    var tasks = 
     Enumerable.Range(0, ConfigReader.ThreadCount) 
     .Select(i => Task.Run(() => new XyzServices().ProcessXyz())); 

    await Task.WhenAll(tasks); 
} 
+0

Ho letto in precedenza che attendere i compiti non è ciò che inizia la loro esecuzione, che in realtà iniziano immediatamente o nei dintorni. È corretto? Potrebbe complicare le tue prime affermazioni. –

+0

@BenKnoble, è un punto giusto, ho chiarito. – Jodrell

+0

Se le funzioni che si stanno chiamando sono asincrone, non è necessario raggrupparle in un 'Task.Run'. Tuttavia, è importante realizzare un'attività asincrona che inizi immediatamente, sul thread corrente, e cambi solo contesto una volta che viene eseguito in una chiamata asincrona stessa. Per le funzioni pesanti della CPU dovresti certamente racchiuderle in un 'Task.Run', per le funzioni che passano rapidamente a una chiamata asincrona (di solito IO), puoi ottenere prestazioni migliori non avviluppandole. – Dorus