C'è un modo nella nuova libreria async dotnet 4.5 per impostare un timeout sul metodo Task.WhenAll
. Voglio recuperare diverse fonti e fermarmi dopo dire 5 secondi e saltare le fonti che non sono state completate.Async Task.WhenAll with timeout
risposta
È possibile combinare la risultante Task
con un Task.Delay()
utilizzando Task.WhenAny()
:
await Task.WhenAny(Task.WhenAll(tasks), Task.Delay(timeout));
Se si vuole raccogliere le attività completate in caso di un timeout:
var completedResults =
tasks
.Where(t => t.Status == TaskStatus.RanToCompletion)
.Select(t => t.Result)
.ToList();
Controllare le sezioni "Early Bailout" e "Task.Delay" da Microsoft Task-Based Asynchronous Pattern Overview.
Primo piano di salvataggio. Un'operazione rappresentata da t1 può essere raggruppata in un WhenAny con un'altra attività t2 e possiamo attendere l'operazione WhenAny. t2 potrebbe rappresentare un timeout, o una cancellazione, o qualche altro segnale che causerà il completamento dell'operazione WhenAny prima del completamento di t1.
Si desidera aggiungere un riepilogo di ciò che dice? – svick
Non sei sicuro del motivo per cui sei tornato su questo post ma il tuo esempio di codice è esattamente quello che descrive il documento (come presumo tu sappia). A richiesta, ho aggiornato la mia risposta con la citazione letterale. –
sembra come il Task. Il sovraccarico WaitAll con il parametro timeout è tutto ciò che serve - se restituisce true, allora sai che sono tutti completati - altrimenti, puoi filtrare su IsCompleted.
if (Task.WaitAll(tasks, myTimeout) == false)
{
tasks = tasks.Where(t => t.IsCompleted);
}
...
Penso che queste attività siano tutte iniziate da soli thread e le nuove funzioni asincrone no, ma correggimi se sbaglio. Sto solo iniziando questa nuova roba asincrona. – broersa
'Task.WaitAll()' sta bloccando, quindi non è una buona idea usarlo in C# 5, se puoi evitarlo. – svick
@broersa In primo luogo, penso che tu abbia sbagliato, la relazione tra i thread ei metodi 'Task's o' async' non è così semplice. In secondo luogo, perché dovrebbe essere così importante? – svick
sono giunto alla seguente pezzo di codice che fa quello che mi serviva:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using System.Net.Http;
using System.Json;
using System.Threading;
namespace MyAsync
{
class Program
{
static void Main(string[] args)
{
var cts = new CancellationTokenSource();
Console.WriteLine("Start Main");
List<Task<List<MyObject>>> listoftasks = new List<Task<List<MyObject>>>();
listoftasks.Add(GetGoogle(cts));
listoftasks.Add(GetTwitter(cts));
listoftasks.Add(GetSleep(cts));
listoftasks.Add(GetxSleep(cts));
List<MyObject>[] arrayofanswers = Task.WhenAll(listoftasks).Result;
List<MyObject> answer = new List<MyObject>();
foreach (List<MyObject> answers in arrayofanswers)
{
answer.AddRange(answers);
}
foreach (MyObject o in answer)
{
Console.WriteLine("{0} - {1}", o.name, o.origin);
}
Console.WriteLine("Press <Enter>");
Console.ReadLine();
}
static async Task<List<MyObject>> GetGoogle(CancellationTokenSource cts)
{
try
{
Console.WriteLine("Start GetGoogle");
List<MyObject> l = new List<MyObject>();
var client = new HttpClient();
Task<HttpResponseMessage> awaitable = client.GetAsync("http://ajax.googleapis.com/ajax/services/search/web?v=1.0&q=broersa", cts.Token);
HttpResponseMessage res = await awaitable;
Console.WriteLine("After GetGoogle GetAsync");
dynamic data = JsonValue.Parse(res.Content.ReadAsStringAsync().Result);
Console.WriteLine("After GetGoogle ReadAsStringAsync");
foreach (var r in data.responseData.results)
{
l.Add(new MyObject() { name = r.titleNoFormatting, origin = "google" });
}
return l;
}
catch (TaskCanceledException)
{
return new List<MyObject>();
}
}
static async Task<List<MyObject>> GetTwitter(CancellationTokenSource cts)
{
try
{
Console.WriteLine("Start GetTwitter");
List<MyObject> l = new List<MyObject>();
var client = new HttpClient();
Task<HttpResponseMessage> awaitable = client.GetAsync("http://search.twitter.com/search.json?q=broersa&rpp=5&include_entities=true&result_type=mixed",cts.Token);
HttpResponseMessage res = await awaitable;
Console.WriteLine("After GetTwitter GetAsync");
dynamic data = JsonValue.Parse(res.Content.ReadAsStringAsync().Result);
Console.WriteLine("After GetTwitter ReadAsStringAsync");
foreach (var r in data.results)
{
l.Add(new MyObject() { name = r.text, origin = "twitter" });
}
return l;
}
catch (TaskCanceledException)
{
return new List<MyObject>();
}
}
static async Task<List<MyObject>> GetSleep(CancellationTokenSource cts)
{
try
{
Console.WriteLine("Start GetSleep");
List<MyObject> l = new List<MyObject>();
await Task.Delay(5000,cts.Token);
l.Add(new MyObject() { name = "Slept well", origin = "sleep" });
return l;
}
catch (TaskCanceledException)
{
return new List<MyObject>();
}
}
static async Task<List<MyObject>> GetxSleep(CancellationTokenSource cts)
{
Console.WriteLine("Start GetxSleep");
List<MyObject> l = new List<MyObject>();
await Task.Delay(2000);
cts.Cancel();
l.Add(new MyObject() { name = "Slept short", origin = "xsleep" });
return l;
}
}
}
La mia spiegazione è nel mio blogpost: http://blog.bekijkhet.com/2012/03/c-async-examples-whenall-whenany.html
Partenza un combinatore un'attività personalizzata proposto in http://tutorials.csharp-online.net/Task_Combinators
async static Task<TResult> WithTimeout<TResult>
(this Task<TResult> task, TimeSpan timeout)
{
Task winner = await (Task.WhenAny
(task, Task.Delay (timeout)));
if (winner != task) throw new TimeoutException();
return await task; // Unwrap result/re-throw
}
Non ho provato t ancora.
a) Il collegamento è rotto. b) Funziona per un singolo compito, che non è quello che l'OP ha chiesto. – i3arnon
Oltre alla risposta di svick, i seguenti lavori per me quando ho dovuto aspettare un paio di compiti da completare, ma hanno per elaborare qualcosa di diverso, mentre io sto aspettando:
Task[] TasksToWaitFor = //Your tasks
TimeSpan Timeout = TimeSpan.FromSeconds(30);
while(true)
{
await Task.WhenAny(Task.WhenAll(TasksToWaitFor), Task.Delay(Timeout));
if(TasksToWaitFor.All(a => a.IsCompleted))
break;
//Do something else here
}
Quello che descrivi sembra come una domanda molto comune, ma non ho potuto trovare da nessuna parte un esempio di questo. E ho cercato un sacco ... ho finalmente creato il seguente:
TimeSpan timeout = TimeSpan.FromSeconds(5.0);
Task<Task>[] tasksOfTasks =
{
Task.WhenAny(SomeTaskAsync("a"), Task.Delay(timeout)),
Task.WhenAny(SomeTaskAsync("b"), Task.Delay(timeout)),
Task.WhenAny(SomeTaskAsync("c"), Task.Delay(timeout))
};
Task[] completedTasks = await Task.WhenAll(tasksOfTasks);
List<MyResult> = completedTasks.OfType<Task<MyResult>>().Select(task => task.Result).ToList();
presumo qui un metodo che restituisce SomeTaskAsync Task <MyResult>.
Dai membri di Task completati, solo le attività di tipo MyResult sono le nostre attività che sono riuscite a battere il tempo. Task.Delay restituisce un tipo diverso. Ciò richiede un po 'di compromesso sulla digitazione, ma funziona comunque magnificamente e abbastanza semplice.
(L'array può, naturalmente, essere costruito dinamicamente utilizzando una query + ToArray).
- Si noti che questa implementazione non richiede SomeTaskAsync per ricevere un token di cancellazione.
penso che una più chiara opzione, più robusto che anche does exception handling right sarebbe quella di utilizzare Task.WhenAny
su ogni attività insieme a un timeout task, passare attraverso tutte le attività completate e filtrare i timeout e utilizzare await Task.WhenAll()
invece di Task.Result
a raccogliere tutti i risultati.
Ecco una soluzione di lavoro completo:
static async Task<TResult[]> WhenAll<TResult>(IEnumerable<Task<TResult>> tasks, TimeSpan timeout)
{
var timeoutTask = Task.Delay(timeout).ContinueWith(_ => default(TResult));
var completedTasks =
(await Task.WhenAll(tasks.Select(task => Task.WhenAny(task, timeoutTask)))).
Where(task => task != timeoutTask);
return await Task.WhenAll(completedTasks);
}
Ci sono due eventi, quando ci sono problemi di prestazioni? Il secondo WhenAll è quello di annullare la chiusura di una attività < >? Puoi spiegare questo per favore? –
@MenelaosVergis Il primo 'Task.WhenAll' viene eseguito su attività che restituiscono attività completate (ad esempio i risultati di' Task.WhenAny's). Quindi filtro queste attività con una clausola where. Finalmente uso 'Task.WhenAll' su queste attività per estrarre i loro risultati effettivi. Tutti questi compiti dovrebbero già essere completati a questo punto. – i3arnon
Oltre al timeout, controllo anche la cancellazione che è utile se si sta costruendo una web app.
public static async Task WhenAll(
IEnumerable<Task> tasks,
int millisecondsTimeOut,
CancellationToken cancellationToken)
{
using(Task timeoutTask = Task.Delay(millisecondsTimeOut))
using(Task cancellationMonitorTask = Task.Delay(-1, cancellationToken))
{
Task completedTask = await Task.WhenAny(
Task.WhenAll(tasks),
timeoutTask,
cancellationMonitorTask
);
if (completedTask == timeoutTask)
{
throw new TimeoutException();
}
if (completedTask == cancellationMonitorTask)
{
throw new OperationCanceledException();
}
await completedTask;
}
}
- 1. attendono Task.WhenAll() vs Task.WhenAll() Wait()
- 2. Come utilizzare ES8 async/await with streams?
- 3. Task.WhenAll() - crea una nuova discussione?
- 4. Come utilizzare correttamente Task.WhenAll()
- 5. Task.WhenAll result ordering
- 6. Ottenere risultato da Task.WhenAll
- 7. Come posso annullare Task.WhenAll?
- 8. riscrivere il codice C# utilizzando Task.WhenAll in F #
- 9. Async attendono in LINQ selezionare
- 10. Ottenere i valori di ritorno da Task.WhenAll
- 11. Come posso attendere Task.WhenAll (...) .ContinueWith (AnotherAwaitable)?
- 12. nidificati Async/attendono Non sembra essere Scaling
- 13. Esegui attività parallele con async/attendi
- 14. Async await e parallel
- 15. attende Task.WhenAll (tasks) Gestione eccezioni, registra tutte le eccezioni dalle attività
- 16. Come fare Async nella funzione WebJob di Azure
- 17. Dove sono i metodi Async FIle.ReadAll *** Async/WriteAll *** Async/AppendAll *** Async?
- 18. async all'interno di un codice LINQ - Chiarimento?
- 19. MessageQueue e Async/Await
- 20. Equivalenza di "With ... End With" in C#?
- 21. Async Deadlock?
- 22. Fornire un valore di timeout quando si utilizza @Async per un metodo utilizzando Spring 3.0
- 23. gelsomino 2 - Async richiamata non è stato invocato all'interno timeout specificato da jasmine.DEFAULT_TIMEOUT_INTERVAL
- 24. async computation does not catch OperationCancelledException
- 25. denominata funzione lambda async
- 26. Django haystack with elasticsearch, indexing issue
- 27. Limitazione del thread del semaforo con async/attendi
- 28. Java: timeout timeout socket socket
- 29. Timeout memorizzato e SqlCommand Timeout
- 30. Spring Async non funziona
Questo ha il più upvotes, ma sappiamo se questo è ora un approccio valido per realizzare questo? – TheJediCowboy
@CitadelCSAlum Cosa intendi? Questo codice fa ciò che viene chiesto. Se non mi credi, puoi leggere la documentazione o provarla tu stesso. – svick
Sebbene questa sia la risposta accettata, fa esattamente ciò che è stato descritto nella domanda? Se ho capito bene, se il timeout si verifica prima che tutte le attività siano state completate, non viene ricevuto alcun risultato (anche se alcune delle attività sono state completate). Ho ragione? Stavo cercando qualcosa che consenta di estrarre i risultati da diversi compiti, prendendo solo quelli che hanno superato il timeout, indipendentemente dal fatto che il resto delle attività non sia riuscito a farlo. Vedi la mia risposta qui sotto. –