2014-09-18 11 views
7

Avrei bisogno del tuo aiuto in quanto segue. Per quasi un mese, ho letto per quanto riguarda i compiti e asincrono.async Attività <HttpResponseMessage> Get VS HttpResponseMessage Get

Ho voluto provare a implementare la mia nuova conoscenza acquisita, in un semplice progetto wep api. Ho i seguenti metodi ed entrambi funzionano come previsto:

public HttpResponseMessage Get() 
{ 
     var data = _userServices.GetUsers(); 
     return Request.CreateResponse(HttpStatusCode.OK, data); 
} 

public async Task<HttpResponseMessage> Get() 
{ 
     var data = _userServices.GetUsers(); 


     return await Task<HttpResponseMessage>.Factory.StartNew(() => 
     { 
      return Request.CreateResponse(HttpStatusCode.OK, data); 
     }); 
} 

Quindi la domanda. Ho provato a usare il violinista e vedere qual è la differenza tra questi due. Quello asincrono è un po 'più veloce, ma a parte questo, qual è il vero vantaggio nell'implementare qualcosa del genere in una web api?

+0

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. –

+0

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 !! –

risposta

2

Ha più senso dove si sta verificando la chiamata con le principali operazioni di I/O. Sì, Async è più veloce perché libera il thread di richiesta per il tempo in cui vengono eseguite le operazioni. Pertanto, dal punto di vista del server Web, si restituisce un thread al pool che può essere utilizzato dal server per eventuali future chiamate in arrivo.

Quindi per es. quando si esegue un'operazione di ricerca su server SQL, è consigliabile eseguire async e visualizzare i vantaggi in termini di prestazioni.

È utile per la scalabilità che coinvolge più server.

Quindi, ad es. quando SearchRecordAsync invia il proprio SQL al database, restituisce un'attività incompleta e quando la richiesta raggiunge l'attesa, restituisce il thread di richiesta al pool di thread. Successivamente, al termine dell'operazione DB, un thread di richiesta viene prelevato dal pool di thread e utilizzato per continuare la richiesta.

Anche se non si sta utilizzando, operazioni SQL, diciamo che si desidera inviare una e-mail a 10 persone. In questo caso anche l'asincrono ha più senso.

Async è anche molto utile per mostrare il progresso dell'evento lungo. Quindi l'utente otterrà comunque la GUI attiva, mentre l'attività è in esecuzione in background.

Per capire, si prega di dare un'occhiata a questo esempio.

Qui sto cercando di avviare un'attività chiamata invia posta. Interim Voglio aggiornare il database, mentre lo sfondo sta eseguendo l'attività di invio della posta.

Dopo l'aggiornamento del database, è in attesa del completamento del task di invio della posta. Tuttavia, con questo approccio è abbastanza chiaro che posso eseguire attività in background e continuare comunque con il thread (principale) originale.

using System; 
using System.Threading; 
using System.Threading.Tasks; 

public class Program 
{ 
    public static void Main() 
    { 
     Console.WriteLine("Starting Send Mail Async Task"); 
     Task task = new Task(SendMessage); 
     task.Start(); 
     Console.WriteLine("Update Database"); 
     UpdateDatabase(); 

     while (true) 
     { 
      // dummy wait for background send mail. 
      if (task.Status == TaskStatus.RanToCompletion) 
      { 
       break; 
      } 
     } 

    } 

    public static async void SendMessage() 
    { 
     // Calls to TaskOfTResult_MethodAsync 
     Task<bool> returnedTaskTResult = MailSenderAsync(); 
     bool result = await returnedTaskTResult; 

     if (result) 
     { 
      UpdateDatabase(); 
     } 

     Console.WriteLine("Mail Sent!"); 
    } 

    private static void UpdateDatabase() 
    { 
     for (var i = 1; i < 1000; i++) ; 
     Console.WriteLine("Database Updated!"); 
    } 

    private static async Task<bool> MailSenderAsync() 
    { 
     Console.WriteLine("Send Mail Start."); 
     for (var i = 1; i < 1000000000; i++) ; 
     return true; 
    } 
} 
+0

Mille grazie per la risposta.Diciamo che vogliamo costruire una web api che deve servire quante più richieste possibili al minuto per un grande volume di e-commerce. Non abbiamo operazioni di I/O, ma assumiamo che abbiamo alcune costose operazioni SQL. Se dovessi decorare i miei endpoint principali come asincroni, sarebbe un buon suggerimento? –

+0

Ehi amico, ho provato con il semplice esempio cosa intendevo con async, è come il threading ma è meno mal di testa perché il compilatore fa tutto per noi. – codebased

0

Utilizzando async sul server in grado di migliorare notevolmente la scalabilità in quanto consente di liberare il filo che serve la richiesta per gestire altre richieste mentre l'operazione async è in corso. Ad esempio in un'operazione IO sincrona, il thread verrebbe sospeso e non fare nulla fino a quando l'operazione non verrà completata e non sarà disponibile per servire un'altra richiesta.

Detto questo, utilizzando Task.Factory.StartNewinizia un altro thread in modo da non ottenere i benefici di scalabilità a tutti. La tua discussione originale può essere riutilizzata, ma hai scaricato il lavoro su un'altra discussione in modo da non avere alcun beneficio netto. infatti c'è un costo di passare a un altro thread, ma questo è minimo.

Le operazioni veramente asincrone non avviano un thread e vorrei verificare se esiste un'operazione del genere o se è possibile scrivere per Request.CreateResponse. Quindi il tuo codice sarebbe molto più scalabile. In caso contrario, è meglio attenersi all'approccio sincrono.

21

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); 
}