Jetzt, da wir wissen, was auf c # 5 zukommt , haben wir offenbar noch eine Möglichkeit, die Auswahl der beiden neuen Schlüsselwörter für " Asynchrony " zu beeinflussen, die gestern von Anders Heijsberg auf der PDC10 angekündigt wurden .
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 hat eine Erklärung für die Auswahl der aktuellen zwei Schlüsselwörter und die Art und Weise, wie sie in Usability-Studien missverstanden wurden. Die Kommentare haben mehrere andere Aussagen.
Bitte - ein Vorschlag pro Antwort, Duplikate werden geknackt.
Antworten:
Da mir die Bedeutung / Notwendigkeit von nicht klar ist
async
, kann ich nicht wirklich darüber streiten, aber mein bester Vorschlag für das Ersetzenawait
ist:yield while
(schau! keine neuen Keywords)Hinweis mit Gedanken über das ein bisschen mehr, frage ich mich , ob die Wiederverwendung von
while
auf diese Weise eine gute Idee ist - die natürliche Tendenz danach eine boolean zu erwarten wäre.(Denkt, gute Keywords zu finden ist wie gute Domainnamen zu finden :)
quelle
while(x) {...}
beiden ausführen , wenn diesx
falsch ist.while
. Wenn Sie ein Verb wie hinzufügendo
, erhalten Siedo {...} while (x)
, das den Körper unabhängig von x (mindestens einmal) ausführt. Ihr Vorschlag vonyield while
scheint sehr ähnlich zu seindo while
, aber mit entgegengesetzten Garantien für die Ausführung des Verbs, was ein bisschen irreführend sein könnte (aber nicht sehr wichtig). Das, was ich am wenigsten mag,yield
ist, dass es die Implementierung eines Mechanismus impliziert. Der springende Punkt beiasync
/await
ist, dass Sie eine asynchrone Operation in einem synchronen Stil schreiben.yield
bricht diesen synchronen Stil.await
Schlüsselwort vom Kontext erkannt, sodass Sie nach wie vor eine Methode oder Variable mit dem Namen "await" haben können, wenn Sie dies möchten. Bis zu einem gewissen Grad denke ich, dass die Verwendung eines neuen Schlüsselworts für neue Funktionen weniger verwirrend ist als die Wiederverwendung eines vorhandenen Schlüsselworts, um mehr als eine Sache zu bedeuten. (übertriebenes Beispiel: dangermouse.net/esoteric/ook.html )Wie wäre es, wenn Sie kein Keyword hätten?
Ich möchte, dass der Compiler erkennt, dass ich in den meisten Fällen, wenn ich eine asynchrone Methode aufrufe, das Ergebnis davon haben möchte.
Das ist es. Der Grund, warum die Leute Schwierigkeiten haben, sich ein Schlüsselwort für diese Sache auszudenken, ist, dass es so ist, als hätte man ein Schlüsselwort für "Mach das, was du machen würdest, wenn die Dinge vollkommen normal wären". Dies sollte die Standardeinstellung sein und kein Schlüsselwort erfordern.
Aktualisieren
Ich schlug ursprünglich vor, dass der Compiler mit der Typinferenz klug werden sollte, um herauszufinden, was zu tun ist. Wenn Sie dies weiter überlegen, würde ich die vorhandene Implementierung im CTP beibehalten, aber ein paar triviale Ergänzungen vornehmen, um die Fälle zu reduzieren, in denen Sie das
await
Schlüsselwort explizit verwenden müssten .Wir erfinden ein Attribut:
[AutoAwait]
. Dies kann nur auf Methoden angewendet werden. Eine Möglichkeit, dies auf Ihre Methode anzuwenden, besteht darin, es zu markierenasync
. Sie können es aber auch von Hand machen, zB:In einer beliebigen
async
Methode geht der Compiler dann davon ausDownloadDocumentAsync
, dass Sie auf einen Aufruf von warten möchten , sodass Sie ihn nicht angeben müssen. Jeder Aufruf dieser Methode wartet automatisch darauf.Wenn Sie nun "clever" werden und die erhalten möchten
Task<Document>
, verwenden Sie einen Operatorstart
, der nur vor einem Methodenaufruf angezeigt werden kann:Ordentlich, denke ich. Jetzt bedeutet ein einfacher Methodenaufruf, was es normalerweise bedeutet: Warten Sie, bis die Methode abgeschlossen ist. Und
start
weist auf etwas anderes hin: Warten Sie nicht.Bei Code, der außerhalb einer
async
Methode angezeigt wird, können Sie eine Methode nur aufrufen,[AutoAwait]
indem Sie ihm ein Präfix voranstellenstart
. Dadurch müssen Sie Code schreiben, der dieselbe Bedeutung hat, unabhängig davon, ob er in einerasync
Methode enthalten ist oder nicht.Dann werde ich gierig! :)
Erstens möchte ich mich
async
auf Schnittstellenmethoden beziehen:Dies bedeutet im Grunde, dass die implementierende Methode zurückkehren muss
Task<int>
oder etwas Kompatiblesawait
, und dass Aufrufer der Methode[AutoAwait]
Verhalten erhalten.Auch wenn ich die obige Methode implementiere, möchte ich schreiben können:
Task<int>
Als Rückgabetyp muss ich also nicht erwähnen .Außerdem möchte ich mich
async
auf Delegiertypen anwenden (die schließlich wie Schnittstellen mit einer Methode sind). So:Ein
async
Delegierter hat - Sie haben es erraten -[AutoAwait]
Verhalten. Von einerasync
Methode aus können Sie sie aufrufen und sie wird automatischawait
bearbeitet (es sei denn, Sie wählen nurstart
diese). Und wenn Sie sagen:Das funktioniert einfach Es ist kein Methodenaufruf. Es wurde noch keine Aufgabe gestartet - eine
async delegate
ist keine Aufgabe. Es ist eine Fabrik für Aufgaben. Sie können sagen:Damit wird eine Aufgabe gestartet und es wird gewartet, bis sie abgeschlossen ist und Sie das Ergebnis erhalten. Oder du kannst sagen:
Wenn Sie also eine
async
Methode delegieren möchten , müssen Sie wissen, wie man einenasync delegate
Typ verwendet. Also anstattFunc
du musst sagenAsyncFunc
, und so weiter. Eines Tages könnte dies durch eine verbesserte Typinferenz behoben werden.Eine andere Frage ist, was passieren soll, wenn Sie sagen, dass Sie mit einer normalen (nicht asynchronen) Methode beginnen. Offensichtlich wäre ein Kompilierungsfehler die sichere Option. Es gibt aber auch andere Möglichkeiten.
quelle
var
, möglicherweise einen langen expliziten Typnamen ersetzen zu müssen, und auch zwischen demawait
Fall und dem Fall, in dem jemand versehentlich die asynchrone Methode anstelle der normalen synchronen Methode aufgerufen hat, zweideutig ist . Es erscheint zunächst intuitiv, verstößt jedoch gegen das Prinzip der geringsten Überraschung.var
? Ich frage mich, ob Sie auf die vorherige Überarbeitung meiner Antwort antworten ... Ich habe sie komplett umgeschrieben. Sie können sich diesen Vorschlag nun wie folgt vorstellen: Wenn die Methode mit einem speziellen Attribut gekennzeichnet ist, wird dasawait
Schlüsselwort automatisch vor den Aufrufen dieser Methode eingefügt (es sei denn, Sie unterdrücken dies mit demstart
Präfix). Alles bleibt genau wie im CTP undvar
funktioniert daher einwandfrei.public async Task<int> FooAsync()
.(Wenn du es nicht verstehst, lies Erics Blog-Eintrag . Zumindest ist es besser als
for sooth Romeo wherefore art thou AsyncFetch(…)
)quelle
Ich denke,
async
ist in Ordnung, aber vielleicht liegt das daran, dass ich es mit asynchronen ASP.NET-Seiten verbinde - dieselbe Idee.Für das
await
Keyword bevorzuge ichcontinue after
oderresume after
.Ich nicht wie
yield
oder eine seiner Varianten, da die Semantik so ist , dass das Verfahren kann nie Ausführung tatsächlich ergibt; es kommt auf den zustand der aufgabe an.quelle
resume after
fürawait
. Vielleichtasync
könnte angerufen werdenresumable
.after
, hat dercontinue after
Ansatz einen starken Implementierungsvorteil: Er enthält ein aktuell vorhandenes kontextbezogenes Schlüsselwort, jedoch mit einer Syntax, die nicht mit der aktuellen Verwendung kompatibel ist. Das garantiert, dass der Zusatz niemals existierenden Code zerstört. Bei der Verwendung eines völlig neuen Schlüsselworts muss die Implementierung mögliche Verwendungen des Wortes als Bezeichner für älteren Code berücksichtigen, was sehr schwierig werden kann.Ich habe auch Kommentare zu Erics Blog hinzugefügt. Ich sehe keine Probleme bei der Verwendung desselben Keywords
async
Ich drücke nur aus, dass ich die Datei asynchron herunterladen möchte. Hier gibt es ein bisschen Redundanz, "async" erscheint zweimal, weil es auch im Methodennamen steht. Der Compiler könnte besonders clever sein und die Konvention erkennen, dass mit "Async" endende Methoden infakte asynchrone Methoden sind, und diese für uns in den kompilierten Code einfügen. Stattdessen möchten Sie vielleicht einfach anrufen
im Gegensatz zu den synchronen zu nennen
Heck, sollten wir auch in der Lage sein, sie auf die gleiche Weise zu definieren, da das Schlüsselwort async in unserer Deklaration enthalten ist, warum müssen wir jedem Methodennamen manuell "Async" hinzufügen - der Compiler kann dies für uns tun.
quelle
async
Tatsache , dass das Schlüsselwort für die Methode nur eine Kleinigkeit ist (wenn ich es richtig verstanden habe), frage ich mich, ob es nicht das Beste wäre, das Gegenteil von dem zu tun, was Sie vorschlagen:async
die Methode aufzugeben und sie einfach zu verwenden wo sie derzeit habenawait
.async Task<Byte[]> DownloadFile(...)
eher alsTask<Byte[]> DownloadFileAsync(...)
(Letzteres ist sowieso die kompilierte Signatur). So oder so funktioniert.async = task - Ändert eine Funktion, um eine Aufgabe zurückzugeben. Warum also nicht das Schlüsselwort "task" verwenden?
wait = finish - Wir müssen nicht unbedingt warten, aber die Aufgabe muss "beendet" sein, bevor das Ergebnis verwendet wird.
quelle
Ich mag
yield until
.yield while
, bereits vorgeschlagen, ist großartig und führt keine neuen Keywords ein, aber ich denke, "bis" erfasst das Verhalten ein wenig besser.Ich denke, das
yield <something>
ist eine großartige Idee, denn Yield fängt bereits die Idee ein, den Rest der Methode so gut fortzusetzen. Vielleicht kann sich jemand ein besseres Wort als "bis" vorstellen.quelle
Ich möchte nur meine Stimme für den Vorschlag von Aaron G registrieren
comefrom
- die erste angemessene Verwendung, die ich von der COMEFROM- Erklärung von INTERCAL gesehen habe . Die Idee ist, dass es das Gegenteil von GOTO ist ( von der GOTO-Anweisung wegzuspringen ), indem es einen Platz in Ihrem Code schafft , zur COMEFROM-Anweisung zu springen.quelle
Task<T>
Wie wäre es,start
wenn Sie, da es sich um s handelt, als Schlüsselwort vor der Anweisung Folgendes verwenden:start var document = FetchAsync(urls[i]);
quelle
finish
wäre vielleicht noch besser alsstart
?Es ist erwähnenswert, dass F # das
async
Schlüsselwort auch in seinen asynchronen Workflows verwendet, was ziemlich genau der neuen asynchronen Funktionalität in C # 5 entspricht. Deshalb würde ich das auch so lassenFür das
await
Schlüsselwort in F # verwenden sie einfachlet!
anstelle vonlet
. C # hat nicht die gleiche Zuweisungssyntax, daher benötigen sie etwas auf der rechten Seite des=
Zeichens. Wie Benjol sagte, funktioniert es genauso wieyield
es fast eine Variante davon sein sollte.quelle
do!
, aber du wusstest, dass ...yield async FetchAsync(..)
Dies passt perfekt zu dem
async
Modifikator, den Sie für die aufgerufene Methode benötigen. Und auch die Semantik der aktuell ,yield return
das heißt, Sie zurückkommen und Ausbeuten Ausführung an das Aufzählen Code während in diesem Fall sind Sie Ihre Ausführung der asynchronen Methode ergeben.Stellen Sie sich vor, wenn es in Zukunft andere Verwendungszwecke für geben sollte
yield
, könnten wir ein "yield x
where x" als neue glänzende Funktion hinzufügen, anstatt all diese verschiedenen Schlüsselwörter zu haben, um zumeist das Gleiche zu tun und die Ausführung zu ermöglichen.Ehrlich gesagt verstehe ich das Argument, dass die Hinrichtung nicht möglich ist, nicht ganz. Ist der Sinn des Aufrufs einer anderen Methode nicht bereits, diese Methode auszuführen? Egal ob asynchron oder nicht? Ich vermisse etwas hier?
Und gut für Sie, wenn die
async
Rückgabe synchron erfolgt, das Schlüsselwort jedoch vorhanden ist, um anzuzeigen, dass die Methode wahrscheinlich asynchron ausgeführt wird und Sie die Ausführung für eine andere Methode ausgeben. Ihre Methode sollte dies berücksichtigen, unabhängig davon, ob die Methode tatsächlich asynchrone Aufrufe ausführt oder nicht.IMO Ich denke, dass die verschiedenen Fälle, in denen keine Ergebnisse erzielt werden, ein Implementierungsdetail sind. Ich würde lieber für Konsistenz in der Sprache bürgen (dh wiederverwenden
yield
).quelle
Wie wäre es mit
complete
"Ich möchte, dass die Aufgabe erledigt wird"?quelle
task
(für Methodendeklaration) undasync
(im Methodenkörper)quelle