Mam następującą operację w utworzonym przeze mnie interfejsie API sieci Web:
// GET api/<controller>
[HttpGet]
[Route("pharmacies/{pharmacyId}/page/{page}/{filter?}")]
public CartTotalsDTO GetProductsWithHistory(Guid pharmacyId, int page, string filter = null ,[FromUri] bool refresh = false)
{
return delegateHelper.GetProductsWithHistory(CustomerContext.Current.GetContactById(pharmacyId), refresh);
}
Wywołanie tej usługi sieciowej odbywa się za pośrednictwem wywołania Jquery Ajax w następujący sposób:
$.ajax({
url: "/api/products/pharmacies/<%# Farmacia.PrimaryKeyId.Value.ToString() %>/page/" + vm.currentPage() + "/" + filter,
type: "GET",
dataType: "json",
success: function (result) {
vm.items([]);
var data = result.Products;
vm.totalUnits(result.TotalUnits);
}
});
Widziałem kilku programistów, którzy implementują poprzednią operację w ten sposób:
// GET api/<controller>
[HttpGet]
[Route("pharmacies/{pharmacyId}/page/{page}/{filter?}")]
public async Task<CartTotalsDTO> GetProductsWithHistory(Guid pharmacyId, int page, string filter = null ,[FromUri] bool refresh = false)
{
return await Task.Factory.StartNew(() => delegateHelper.GetProductsWithHistory(CustomerContext.Current.GetContactById(pharmacyId), refresh));
}
Muszę jednak powiedzieć, że GetProductsWithHistory () to dość długa operacja. Biorąc pod uwagę mój problem i kontekst, jakie korzyści przyniesie mi asynchroniczna operacja interfejsu webAPI?
c#
jquery
ajax
asp.net-web-api
async-await
David Jiménez Martínez
źródło
źródło
async Task<T>
. Pamiętaj, AJAX został zaimplementowany zanim jeszcze istniał TPL :)GetProductsWithHistoryAsync()
zwrotuTask<CartTotalsDTO>
. Zapisanie kontrolera w trybie asynchronicznym może przynieść korzyści, jeśli zamierzasz migrować wywołania, które wywołuje, aby były również asynchroniczne; następnie zaczniesz czerpać korzyści z części asynchronicznych podczas migracji pozostałych.Odpowiedzi:
W twoim konkretnym przykładzie operacja nie jest w ogóle asynchroniczna, więc to, co robisz, to asynchronizacja przez synchronizację. Po prostu zwalniasz jeden wątek i blokujesz inny. Nie ma powodu, ponieważ wszystkie wątki są wątkami puli wątków (w przeciwieństwie do aplikacji GUI).
Od Czy należy uwidaczniać otoki synchroniczne dla metod asynchronicznych?
Jednak podczas wykonywania wywołań
async
interfejsu WebAPI, w których występuje rzeczywista operacja asynchroniczna (zwykle we / wy) zamiast blokowania wątku, który siedzi i czeka na wynik, wątek wraca do puli wątków, dzięki czemu może wykonać inną operację. Oznacza to, że Twoja aplikacja może zrobić więcej przy mniejszych zasobach, a to poprawia skalowalność.źródło
await Task.Run(() => CPUIntensive())
) jest bezużyteczne w asp.net. Nic na tym nie zyskujesz. Po prostu zwalniasz jeden wątek ThreadPool, aby zająć inny. Jest to mniej wydajne niż zwykłe wywołanie metody synchronicznej.await Task.WhenAll
, aby wykonywać równolegle.Task.Run
jeśli chcesz zrównoleglenie obciążenia w wielu wątkach, ale nie to oznacza „asynchronizacja przez synchronizację”. „async over sync” odwołuje się do tworzenia metody asynchronicznej jako otoki względem metody synchronicznej. Możesz zobaczyć w cytacie w mojej odpowiedzi.Jednym podejściem mogłoby być (z powodzeniem stosowałem to w aplikacjach klientów), aby usługa Windows uruchamiała długie operacje z wątkami roboczymi, a następnie robiła to w usługach IIS, aby zwolnić wątki do momentu zakończenia operacji blokowania: Uwaga, zakłada się, że wyniki są przechowywane w tabeli (wiersze identyfikowane przez jobId), a czystszy proces czyści je kilka godzin po użyciu.
Odpowiadając na pytanie: „Biorąc pod uwagę mój problem i kontekst, jakie korzyści przyniesie mi ustawienie asynchronicznej operacji interfejsu webAPI?” biorąc pod uwagę, że jest to „dość długa operacja”, myślę o wielu sekundach, a nie ms, takie podejście zwalnia wątki IIS. Oczywiście musisz również uruchomić usługę Windows, która sama pobiera zasoby, ale takie podejście może zapobiec zalewowi powolnych zapytań przed kradzieżą wątków z innych części systemu.
źródło