2015-05-25 30 views
11

Próbuję wdrożyć Stream, który obsługuje ReadAsync i WriteAsync, i biorąc pod uwagę spareseness z documentation, mam trudności, aby zrozumieć, jak to zrobić prawidłowo. Konkretnie, w odniesieniu do pozycji kursora strumienia. Podobne pytanie zostało zadane here i here dotyczące starej funkcji BeginRead. Dokumentacja tej funkcji zdawała się wskazywać, że nie powinno się ponownie wywoływać BeginRead, dopóki nie zakończą się żadne oczekujące operacje asynchroniczne.Czy Stream.ReadAsync i Stream.WriteAsync mają zmienić synchronicznie pozycję kursora przed powrotem lub po zakończeniu operacji?

Zważywszy, że BeginRead jest teraz przestarzałeno longer recommended for new development i Stream, najprawdopodobniej znacząco zmienione w celu wdrożenia nowych funkcji ASYNC rzeczy są ponownie niejasny. (EDYCJA: Zwykle tego rodzaju ostrzeżenie oznacza, że ​​nowe funkcje są zaimplementowane bezpośrednio, a stare funkcje wywołują nowe i są nadal dostępne dla kompatybilności wstecznej, ale wydaje się, że tak nie jest w tym przypadku).

The ReadAsyncWriteAsync i funkcje są określone tak, że nie biorą one żądaną pozycję odczytu strumienia/zapisu jako ich Win32counterparts zrobić (bardzo słaby wybór projektu moim zdaniem), ale zamiast polegać na aktualnej pozycji posiadanych przez implementacja strumienia. Taka sytuacja jest w porządku, jeśli jeden z dwóch warunków przytrzymanie:

  1. ReadAsync i WriteAsync musi chwycić bieżącą pozycję kursora do wykorzystania przez operację i aktualizować go tak, jakby operacja zakończona (lub nie aktualizuje go w ogóle), zanim wrócą Task lub
  2. Nie można wykonywać żadnych połączeń, dopóki wszystkie poprzednie połączenia asynchroniczne nie zostaną zakończone.

Poza tymi dwoma warunkami, rozmówca nigdy nie może być pewny stanowiska odczytu lub zapisu nastąpi przy ponieważ w toku operacji asynchronicznych mogą zmieniać pozycję strumienia pomiędzy każdym Seek i zadzwonić do ReadAsync lub WriteAsync. Żaden z tych warunków nie jest udokumentowany jako wymóg, więc zastanawiam się, jak powinien funkcjonować.

Moje testy strukturalne wskazuje na to, że przynajmniej w wersji StreamFileStream, strumień pozycja aktualizuje asynchronicznie, co wydaje się wskazywać, że drugi warunek (tylko jeden czeka operacja dozwolone) jest jeszcze jeden, który jest wymagany, ale wydaje się to poważnym ograniczeniem (z pewnością wyklucza to wszelkiego rodzaju wewnętrzną implementację scatter-gather).

Czy każdy może podać jakiekolwiek wiarygodne informacje, czy stare ograniczenie w postaci BeginRead nadal ma zastosowanie do , czy też nie?

+1

Myślę, że logika stojąca za projektem polega na tym, że strumień ze swej natury nie jest bezpieczny dla wątków; dlatego nie ma sensu, aby uzyskać do niego dostęp podczas gdy operacja asynchroniczna jest w toku (tylko dlatego, że operacja jest asynchroniczna, pozwalając na to, aby twój kod z wyczekiwaniem oczekiwał na odczyt/zapis strumienia bez blokowania, nie oznacza, że ​​dobrym pomysłem jest granie z strumień z innego wątku, podczas gdy ta operacja jest w toku). – Cameron

+0

Biorąc pod uwagę, że 'ReadAsync' odczyta nieznaną liczbę bajtów, w jaki sposób może dokładnie zaktualizować pozycję przed zakończeniem operacji? –

+0

Równoczesne operacje wejścia, nawet jeśli są inicjowane sekwencyjnie, mogą powodować, że wywołanie zwrotne będzie wywoływane jednocześnie. To warunek wyścigowy dla większości wdrożeń strumieniowych. Jest to ogólnie zabronione. – usr

Odpowiedz

8

Czy ktoś może dostarczyć jakichkolwiek wiarygodnych informacji o tym, czy stary BeginRead ograniczenie stosuje się jednak do ReadAsync czy nie?

Te same ograniczenia dotyczą BeginRead i ReadAsync.

Stare metody APM nie są przestarzałe.Nadal są w pełni obsługiwane i nie ma nic złego w ich używaniu. Jednak metody async są znacznie łatwiejsze w użyciu, więc dokumentacja sugeruje ich użycie.

Wszystkie te async „przeciążenia” na tych starych klas zazwyczaj mają jeszcze składać dzwoniąc BeginXXX i EndXXX lub co najwyżej obie opcje nazywamy wspólną metodę (np FileStream.BeginReadAsync). Nigdy nie widziałem żadnego kodu (w ramach lub w inny sposób), który ma metody pakowania APM w stosunku do jednej z nich.

W związku z tym, calling ReadAsync will result in calling BeginRead, więc wszelkie ograniczenia dotyczą obu. Ponadto, ponieważ Stream nie jest bezpieczna dla wątków i nie reklamuje się jako współistniejąca (co jest nieco inne), można bezpiecznie założyć, że nie można jednocześnie zasypać jej żądaniami async.

+0

W przypadku braku dokumentacji, chciałbym żałować, że nie było przynajmniej komentarza gdzieś w kodzie źródłowym wskazującym na to ograniczenie, ale przypuszczam, że wystarczy 30 minut badania kodu źródłowego. Dzięki! – James

+0

Uwielbiam ten komentarz w tej funkcji w wierszu 2023: 'Ten kod musi zostać naprawiony. – James