2015-10-07 12 views
10

Przenieśliśmy projekt z WCF do Web API (SelfHost) i podczas procesu zauważyliśmy ogromne spowolnienie podczas udostępniania aplikacji internetowej. Teraz 40-50 sekund vs 3 sekundy wcześniej.ASP.NET Web API 2 - StreamContent jest bardzo powolny

mam odtworzyć problem w prostej aplikacji konsoli dodając różne Nuget Pacakges dla AspNet.WebApi i OwinSelfHost z poniższego regulatora:

var stream = new MemoryStream(); 
using (var file = File.OpenRead(filename)) 
{ 
    file.CopyTo(stream); 
} 
stream.Position = 0; 

var response = Request.CreateResponse(System.Net.HttpStatusCode.OK); 

/// THIS IS FAST 
response.Content = new ByteArrayContent(stream.ToArray()); 
/// THIS IS SLOW 
response.Content = new StreamContent(stream); 

response.Content.Headers.ContentType = new MediaTypeHeaderValue(System.Web.MimeMapping.GetMimeMapping(filename));    
response.Content.Headers.ContentLength = stream.Length; 

Jak widać z kodu Jedyną różnicą jest korzystanie z StreamContent (slooooow) vs ByteArrayContent.

Aplikacja jest hostowana na maszynie Win10 i jest dostępna z mojego laptopa. Fiddler pokazuje, że uzyskanie pojedynczego pliku o wielkości 1 MB z serwera na mój laptop zajmuje 14 sekund przy użyciu StreamContent, podczas gdy wartość ByteArrayContent jest mniejsza niż 1s.

Należy również pamiętać, że cały plik jest wczytany do pamięci, aby pokazać, że jedyną różnicą jest używana klasa zawartości.

Dziwne jest to, że wydaje się, że jego transfer jest powolny. Serwer odpowiada z nagłówkami szybko/od razu, ale dane zajmuje dużo czasu, aby dotrzeć jak pokazuje Fiddler synchronizacji informacji:

GotResponseHeaders: 07:50:52.800 
ServerDoneResponse: 07:51:08.471 

Kompletna Timing INFO:

== TIMING INFO ============ 
ClientConnected: 07:50:52.238 
ClientBeginRequest: 07:50:52.238 
GotRequestHeaders: 07:50:52.238 
ClientDoneRequest: 07:50:52.238 
Determine Gateway: 0ms 
DNS Lookup:   0ms 
TCP/IP Connect:  15ms 
HTTPS Handshake: 0ms 
ServerConnected: 07:50:52.253 
FiddlerBeginRequest:07:50:52.253 
ServerGotRequest: 07:50:52.253 
ServerBeginResponse:07:50:52.800 
GotResponseHeaders: 07:50:52.800 
ServerDoneResponse: 07:51:08.471 
ClientBeginResponse:07:51:08.471 
ClientDoneResponse: 07:51:08.471 

Overall Elapsed: 0:00:16.233 

Czy ktoś wie co się dzieje pod maską, która może wyjaśnić różnicę w zachowaniu?

+0

Cześć, mam tu dokładnie ten sam problem. czy znalazłeś rozwiązanie w międzyczasie? – DanielG

+1

@DanielG: Obawiam się, że nie, ale wysłałem tutaj raport o błędzie: https://connect.microsoft.com/VisualStudio/feedback/details/1932717/asp-net-bug-issue. Byłoby dobrze, gdybyście głosowali nad nim, a także kliknęli link "Mogę też" (obok Repros). – TommyN

+0

OK, zrobi to. Jedno pytanie: dlaczego nie używasz tylko ByteArrayContent, jeśli masz dane już w pamięci? – DanielG

Odpowiedz

14

Rozwiązaniem mojego problemu dotyczącego samoobsługi OWIN był rozmiar bufora StreamContent. Domyślny konstruktor StreamContent używa domyślnej wartości 0x1000, 4Kb. W sieci gigabitowej przesłanie pliku 26 MB trwa około 7 minut z prędkością ~ 60Kb/s.

const int BufferSize = 1024 * 1024; 
responseMessage = new HttpResponseMessage(); 
responseMessage.Content = new StreamContent(fileStream, BufferSize); 

Modyfikowanie rozmiaru bufora na 1MB zajmuje teraz tylko kilka sekund, aby dokończyć pobieranie.

[EDYCJA] W StreamContent SerializeToStreamAsync wykonuje StreamToStreamCopy, zgodnie z this link wydajność będzie się różnić. Odpowiednia wartość to prawdopodobnie 80K.

0

Po wykonaniu projektów spróbuj przejść z trybu debugowania do wydania. jest to nieoczekiwane ujęcie, które znacznie zwiększyłoby wydajność, o pewną wartość,

+1

Bez obawy obawiam się. – TommyN

3

Mam do czynienia z tym samym problemem tutaj i myślę, że jest on związany z samodzielnym hostowaniem Owin. Właśnie stworzyłem przykładową aplikację Asp.net i hostowałem ją na IIS. W tym przypadku działało to zgodnie z oczekiwaniami.

Wyniki na moim Testsystem podczas pobierania pliku 80 MB:

  • z Streamcontent i SelfHosting: ~ 20 minut
  • z ByteArrayContent i Selfhosting: < 30 sekund
  • z Streamcontent i IIS Hosting: < 30 sekund

Dostępne jest ustawienie konfiguracyjne w ASP.net, którego brakuje w moim hostowanym pro jekt, albo jest błąd w kodzie samoobsługi, jak sądzę.