Teraz, gdy wiemy, co czeka nas na c # 5, najwyraźniej nadal mamy możliwość wpływania na wybór dwóch nowych słów kluczowych dla „ Asynchronii ”, ogłoszonych wczoraj przez Andersa Heijsberga na PDC10 .
async void ArchiveDocuments(List<Url> urls) {
Task archive = null;
for(int i = 0; i < urls.Count; ++i) {
var document = await FetchAsync(urls[i]);
if (archive != null)
await archive;
archive = ArchiveAsync(document);
}
}
Eric Lippert wyjaśnił wybór dwóch aktualnych słów kluczowych oraz sposób, w jaki zostały one źle zrozumiane w badaniach użyteczności. Komentarze mają kilka innych propozycji.
Proszę - jedna sugestia na odpowiedź, duplikaty zostaną zniszczone.
Odpowiedzi:
Biorąc pod uwagę, że nie jestem pewien co do znaczenia / konieczności
async
, tak naprawdę nie mogę się z tym kłócić, ale moja najlepsza propozycja zastąpieniaawait
to:yield while
(patrz! brak nowych słów kluczowych)Zauważmy, że zastanowiwszy się nad tym trochę, zastanawiam się, czy ponowne użycie
while
w ten sposób jest dobrym pomysłem - naturalną tendencją byłoby oczekiwanie później wartości logicznej.(Myśli: znalezienie dobrych słów kluczowych jest jak znalezienie dobrych nazw domen :)
źródło
while(x) {...}
, jeślix
jest to fałsz.while
. Jeśli dodasz czasownik, na przykładdo
, otrzymaszdo {...} while (x)
, który wykonuje ciało niezależnie od x (przynajmniej raz). Twoja sugestiayield while
wydaje się bardzo podobna dodo while
, ale z przeciwnymi gwarancjami wykonywania czasownika, co może być nieco mylące (ale niezbyt wielka sprawa). Najbardziej nie lubię tegoyield
, że implikuje wdrożenie mechanizmu. Sensemasync
/await
jest to, że piszesz asynchroniczną operację w synchronicznym stylu.yield
przełamuje ten styl synchroniczny.await
słowo kluczowe zostanie rozpoznane na podstawie kontekstu, więc nadal możesz mieć metodę lub zmienną o nazwie „czekaj”, jeśli chcesz. W pewnym stopniu uważam, że użycie nowego słowa kluczowego do nowej funkcjonalności jest mniej mylące niż ponowne użycie istniejącego słowa kluczowego w celu oznaczenia więcej niż jednej rzeczy. (przesadzony przykład: dangermouse.net/esoteric/ook.html )Co powiesz na brak słowa kluczowego?
Chciałbym, aby kompilator zdał sobie sprawę, że przez większość czasu, gdy wywołuję metodę asynchroniczną, chcę jej wynik.
Otóż to. Powodem, dla którego ludzie mają trudności z wymyśleniem słowa kluczowego dla tej rzeczy, jest to, że jest to słowo kluczowe dla „rób to, co zrobiłbyś, gdyby wszystko było całkowicie normalne”. To powinno być domyślne, nie wymagać słowa kluczowego.
Aktualizacja
Początkowo zasugerowałem, że kompilator powinien być sprytny z wnioskami o typ, aby dowiedzieć się, co robić. Zastanawiając się nad tym, chciałbym zachować obecną implementację w CTP w obecnej postaci, ale dodam do niej kilka trywialnych dodatków, aby zmniejszyć liczbę przypadków, w których konieczne byłoby
await
jawne użycie słowa kluczowego.Wymyślamy atrybut:
[AutoAwait]
. Można to zastosować tylko do metod. Jednym ze sposobów, aby zastosować to do metody, jest jej oznaczenieasync
. Ale możesz to również zrobić ręcznie, np .:Następnie w każdej
async
metodzie kompilator zakłada, że chcesz poczekać na wywołanieDownloadDocumentAsync
, więc nie musisz go określać. Każde wywołanie tej metody będzie automatycznie na nią czekało.Teraz, jeśli chcesz „uzyskać spryt” i uzyskać
Task<Document>
, użyj operatorastart
, który może pojawić się tylko przed wywołaniem metody:Zgrabnie, tak myślę. Teraz zwykłe wywołanie metody oznacza to, co zwykle oznacza: poczekaj na zakończenie metody. I
start
wskazuje coś innego: nie czekaj.W przypadku kodu, który pojawia się poza
async
metodą, jedynym sposobem na wywołanie[AutoAwait]
metody jest przedrostekstart
. Zmusza to do pisania kodu o tym samym znaczeniu, niezależnie od tego, czy pojawia się wasync
metodzie, czy nie.Potem zaczynam być chciwy! :)
Po pierwsze, chcę
async
zastosować się do metod interfejsu:Zasadniczo oznacza to, że metoda implementująca musi zwrócić
Task<int>
lub coś kompatybilnegoawait
, a osoby wywołujące metodę otrzymają[AutoAwait]
zachowanie.Również po wdrożeniu powyższej metody chcę móc pisać:
Więc nie muszę wspominać
Task<int>
o typie zwrotu.Chcę
async
również zastosować do typów delegowanych (które przecież są jak interfejsy z jedną metodą). Więc:async
Delegat posiada - zgadliście -[AutoAwait]
zachowanie. Zasync
metody możesz ją wywołać, a zostanie ona automatycznieawait
edytowana (chyba że zdecydujesz się tostart
zrobić). A więc jeśli powiesz:To po prostu działa. To nie jest wywołanie metody. Żadne zadanie nie zostało jeszcze uruchomione -
async delegate
nie jest zadaniem. To fabryka do wykonywania zadań. Możesz powiedzieć:A to rozpocznie zadanie i zaczekaj, aż się zakończy i da ci wynik. Lub możesz powiedzieć:
Tak więc jednym z miejsc, w których przecieka „hydraulika”, jest to, że jeśli chcesz delegować
async
metodę, musisz wiedzieć, że używaszasync delegate
typu. Zamiast tegoFunc
musisz powiedziećAsyncFunc
i tak dalej. Chociaż pewnego dnia tego rodzaju rzeczy mogą zostać naprawione przez lepsze wnioskowanie o typie.Innym pytaniem jest, co powinno się stać, jeśli powiesz, że zacznij od zwykłej metody (nie asynchronicznej). Oczywiście błąd kompilacji byłby bezpieczną opcją. Ale są też inne możliwości.
źródło
var
, potencjalnie konieczność zastąpienia długiej, jawnej nazwy typu, a także jest niejednoznaczny międzyawait
przypadkiem a przypadkiem, w którym ktoś przypadkowo wywołał metodę asynchroniczną zamiast normalnej metody synchronicznej. Z początku wydaje się intuicyjny, ale w rzeczywistości narusza zasadę najmniejszego zaskoczenia.var
? Zastanawiam się, czy odpowiadasz na poprzednią wersję mojej odpowiedzi ... Całkowicie ją przepisałem. Możesz teraz pomyśleć o tej sugestii w następujący sposób: jeśli metoda jest oznaczona specjalnym atrybutem, to tak, jakbyawait
słowo kluczowe było automatycznie wstawiane przed wywołaniami tej metody (chyba że pominiesz tostart
przedrostkiem). Wszystko pozostaje dokładnie tak, jak w CTP, a zatemvar
działa dobrze.public async Task<int> FooAsync()
.(jeśli go nie dostaniesz, przeczytaj wpis na blogu Erica . Przynajmniej jest lepszy niż
for sooth Romeo wherefore art thou AsyncFetch(…)
)źródło
Myślę, że
async
jest w porządku, ale może dlatego, że kojarzę go ze stronami asynchronicznymi ASP.NET - ten sam pomysł.Dla
await
słowa kluczowego wolęcontinue after
lubresume after
.I nie jak
yield
lub któregokolwiek z jej wariantów, ponieważ semantyka są takie, że metoda nie może faktycznie uzyskując wykonanie; zależy to od stanu zadania.źródło
resume after
zaawait
. Możeasync
mógłby być nazwanyresumable
.after
,continue after
podejście to ma dużą zaletę implementacyjną: obejmuje obecnie istniejące słowo kluczowe kontekstowe, ale ze składnią niezgodną z bieżącym użyciem. To gwarantuje, że dodanie nigdy nie zepsuje istniejącego kodu. W przypadku użycia zupełnie nowego słowa kluczowego implementacja musi poradzić sobie z możliwym wykorzystaniem tego słowa jako identyfikatora starszego kodu, co może być dość trudne.Dodałem też do komentarzy na blogu Erica, nie widzę problemów z używaniem tego samego słowa kluczowego
async
Wyrażam tylko, że chcę asynchronicznie pobrać plik. Jest tu trochę redundancji, „asynchronizacja” pojawia się dwa razy, ponieważ jest również w nazwie metody. Kompilator może być wyjątkowo sprytny i wykryć konwencję, że metody kończące się na „Async” są w rzeczywistości metodami asynchronicznymi, i dodać to dla nas w skompilowanym kodzie. Zamiast tego możesz po prostu zadzwonić
w przeciwieństwie do wywoływania synchronicznego
Heck, powinniśmy być w stanie zdefiniować je w ten sam sposób, ponieważ słowo kluczowe async znajduje się w naszej deklaracji, dlaczego musimy ręcznie dodać „Async” do nazwy każdej metody - kompilator może to zrobić za nas.
źródło
async
słowo kluczowe w metodzie jest po prostu subtelne (jeśli dobrze zrozumiałem), zastanawiam się, czy najlepszą rzeczą nie byłoby zrobić coś przeciwnego do tego, co sugerujesz: porzucićasync
metodę i po prostu użyć jej gdzie obecnie mająawait
.async Task<Byte[]> DownloadFile(...)
ZamiastTask<Byte[]> DownloadFileAsync(...)
(ten ostatni i tak będzie skompilowanym podpisem). Tak czy inaczej działa.async = zadanie - modyfikuje funkcję, aby zwrócić zadanie, więc dlaczego nie użyć słowa kluczowego „zadanie”?
czekaj = zakończ - niekoniecznie musimy czekać, ale zadanie musi „zakończyć” przed użyciem wyniku.
źródło
Lubię
yield until
.yield while
, już zasugerowany, jest świetny i nie wprowadza żadnych nowych słów kluczowych, ale myślę, że „dopóki” nie uchwyci zachowania nieco lepiej.Uważam, że
yield <something>
to świetny pomysł, ponieważ wydajność już uchwyciła ideę uczynienia reszty metody tak dobrą kontynuacją. Może ktoś wymyśli lepsze słowo niż „do”.źródło
Chcę tylko zarejestrować swój głos na sugestię Aarona G.
comefrom
- pierwsze właściwe zastosowanie, jakie widziałem w oświadczeniu INTERCAL COMEFROM . Chodzi o to, że jest to przeciwieństwo GOTO ( odskakiwanie od instrukcji GOTO), ponieważ powoduje, że pewne miejsce w kodzie przeskakuje do instrukcji COMEFROM.źródło
Skoro mamy do czynienia z
Task<T>
s, to jak użyćstart
słowa kluczowego poprzedzającego instrukcję, jak w:start var document = FetchAsync(urls[i]);
źródło
finish
byłby nawet lepszy niżstart
?Warto zauważyć, że F # używa również
async
słowa kluczowego w swoich obiegach pracy asynchronicznej, co jest właściwie dokładnie tym samym, co nowa funkcja asynchroniczna w C # 5. Dlatego nie zmieniłbym tegoW przypadku
await
słowa kluczowego w języku F # używają po prostulet!
zamiastlet
. C # nie ma tej samej składni przypisania, więc potrzebują czegoś po prawej stronie=
znaku. Jak powiedział Benjol, działa tak samo,yield
więc powinien być niemal wariantem tego.źródło
do!
, ale wiedziałeś, że ...yield async FetchAsync(..)
To doskonale pasuje do
async
modyfikatora, który musisz zastosować do metody, którą wywołujesz. A także semantyczny prąduyield return
, to znaczy, że zwracasz i dajesz wykonanie kodowi wyliczającemu, podczas gdy w tym przypadku dajesz swoje wykonanie metodzie asynchronicznej.Wyobraź sobie, że w przyszłości będą inne zastosowania
yield
, moglibyśmy dodaćyield x
gdzie x jest lśniącą nową funkcją zamiast posiadania tych wszystkich różnych słów kluczowych do robienia głównie tego samego, czyli wykonywania wydajności.Szczerze mówiąc, nie do końca rozumiem argument „nie poddawanie się”. W końcu, czy nie ma sensu wywoływać innej metody w celu „wykonania” tej metody? Niezależnie od tego, czy jest asynchroniczny czy nie? Coś tu brakuje?
I dobrze, jeśli
async
zwroty są synchroniczne, ale słowo kluczowe powinno oznaczać, że istnieje prawdopodobieństwo, że metoda będzie działać asynchronicznie i że wykonasz wykonanie innej metody. Twoja metoda powinna to uwzględnić niezależnie od tego, czy metoda faktycznie wykonuje wywołania asynchroniczne, czy nie.IMO Myślę, że różne przypadki „niepoddawania się” są szczegółami wdrożenia. Wolę ręczyć za spójność w języku (tj. Ponowne użycie
yield
).źródło
A może
complete
jak w „Chcę, aby zadanie zostało wykonane”?źródło
task
(w przypadku deklaracji metody) iasync
(w treści metody)źródło