Come altri hanno sottolineato, il punto di async
su ASP.NET è che libera uno dei thread del pool di thread ASP.NET. Funziona in modo ottimale per operazioni asincrone come le operazioni con collegamenti I/O perché quello è un thread in meno sul server (non c'è thread che "elabora" l'operazione asincrona, as I explain on my blog). Pertanto, il vantaggio principale di async
sul lato server è la scalabilità .
Tuttavia, si desidera evitare Task.Run
(e, peggio ancora, Task.Factory.StartNew
) su ASP.NET. Io chiamo questa "asincronia falsa" perché stanno facendo solo lavori sincroni/bloccanti su un thread pool di thread. Sono utili nelle app di interfaccia utente in cui si desidera spostare il lavoro dal thread dell'interfaccia utente, in modo che l'interfaccia utente rimanga reattiva, ma non dovrebbero (quasi) mai essere utilizzati su ASP.NET o altre app del server.
L'utilizzo di Task.Run
o Task.Factory.StartNew
su ASP.NET riduce effettivamente la scalabilità. Causeranno alcuni interruttori di thread non necessari. Per le operazioni più lunghe, si potrebbe finire per eliminare l'euristica del pool di thread ASP.NET, causando la creazione di thread aggiuntivi e la successiva distruzione inutilmente. Apprendo passo passo i problemi relativi alle prestazioni in another blog post.
Quindi, è necessario pensare a cosa sta facendo ciascuna azione, e se uno di questi deve essere asincrono. Se dovrebbe, allora quell'azione dovrebbe essere asincrona. Nel tuo caso:
public HttpResponseMessage Get()
{
var data = _userServices.GetUsers();
return Request.CreateResponse(HttpStatusCode.OK, data);
}
Che cosa fa esattamente Request.CreateResponse
? Sta solo creando un oggetto risposta. Questo è tutto - solo una fantasia new
. Non c'è nessun I/O in corso, e certamente non è qualcosa che deve essere spinto a un thread in background.
Tuttavia, GetUsers
è molto più interessante. Sembra più una lettura di dati, che è basata su I/O. Se il back-end in grado di scalare (ad esempio, Azure SQL/tavoli/etc), allora si dovrebbe guardare a fare quella async
prima, e una volta che il servizio sta esponendo un GetUsersAsync
, allora questa azione potrebbe diventare async
troppo:
public async Task<HttpResponseMessage> Get()
{
var data = await _userServices.GetUsersAsync();
return Request.CreateResponse(HttpStatusCode.OK, data);
}
Bene , prima di tutto, grazie a tutti per aver risposto. Mi hai dato un po 'di "lavoro a casa" da fare. Capisco che Factory.StartNew è terribile dato che in realtà inizia una nuova discussione su ogni richiesta! Capisco anche che la "operazione asincrona" deve essere inoltrata al repository, ovvero fino a GetUsers (Servizio) -> GetUsersAsync (Repository). Quindi avremo una catena di metodi asincroni, fino al repository. Il repository dovrebbe implementare un modello che supporti operazioni asincrone, ad esempio Asincrono Ado.Net o EntityFramework. –
Se dovessi creare questo Web Api, inizierei con 3 livelli 1) Presentazione 2) Servizio e 3) Repository. Il repository implementerà Async Ado.Net o Entityframework. Inoltre, tutto ciò si verificherà sul thread principale ma con operazioni ASYNCHRONOUS. Ho cercato di "divorare" la teoria nel seguente libro Multithreading In C# 5.0 Cookbook. Sembra che tutta questa conoscenza sia incasinata nella mia testa, quindi scusami, se mi trovi a ripetere cose. Pubblicherò il codice che spiega cosa "penso" capisco. Apprezzerei se tutti voi poteste contribuire di nuovo così attivamente !! –