Maintenant que nous savons ce qui est en réserve pour le c # 5, il y a apparemment encore une ouverture pour nous pour influencer le choix des deux nouveaux mots clés pour ' Asynchrony ' qui ont été annoncés par Anders Heijsberg hier au 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 a une explication du choix des deux mots clés actuels et de la façon dont ils ont été mal compris dans les études d'utilisabilité. Les commentaires ont plusieurs autres propositions.
S'il vous plaît - une suggestion par réponse, les doublons seront supprimés.
Réponses:
Étant donné que je ne suis pas clair sur le sens / la nécessité de
async
, je ne peux pas vraiment m'y opposer, mais ma meilleure suggestion pour le remplacerawait
est:yield while
(regardez! pas de nouveaux mots-clés)Notez qu'après y avoir réfléchi un peu plus, je me demande si la réutilisation
while
de cette manière est une bonne idée - la tendance naturelle serait d'attendre un booléen après.(Pense: trouver de bons mots clés, c'est comme trouver de bons noms de domaine :)
la source
while(x) {...}
non plus, six
est faux.while
. Si vous ajoutez un verbe, commedo
, alors vous obtenezdo {...} while (x)
, ce qui exécute le corps indépendamment de x (au moins une fois). Votre suggestion deyield while
semble très similaire àdo while
, mais avec des garanties opposées d'exécuter le verbe, ce qui pourrait être un peu trompeur (mais pas beaucoup). Ce qui me déplaît le plus,yield
c'est que cela implique la mise en place d'un mécanisme. L'intérêt deasync
/await
est que vous écrivez une opération asynchrone dans un style synchrone.yield
rompt ce style synchrone.await
mot - clé serait reconnu par le contexte, vous pouvez donc toujours avoir une méthode ou une variable nommée "attendre" si vous le souhaitez. Dans une certaine mesure, je pense que l'utilisation d'un nouveau mot clé pour de nouvelles fonctionnalités est moins déroutante que la réutilisation d'un mot clé existant pour signifier plus d'une chose. (exemple exagéré: dangermouse.net/esoteric/ook.html )Que diriez-vous de ne pas avoir de mot-clé?
J'aimerais que le compilateur se rende compte que, la plupart du temps, lorsque j'appelle une méthode asynchrone, je veux le résultat.
C'est ça. La raison pour laquelle les gens ont du mal à trouver un mot-clé pour cette chose est parce que c'est comme avoir un mot-clé pour "faire ce que vous feriez si les choses étaient parfaitement normales". Cela devrait être la valeur par défaut, pas besoin d'un mot clé.
Mise à jour
J'ai suggéré à l'origine que le compilateur devrait être intelligent avec l'inférence de type pour comprendre quoi faire. En réfléchissant davantage à cela, je garderais l'implémentation existante dans le CTP telle qu'elle est, mais j'y ferais quelques ajouts triviaux, afin de réduire les cas où vous auriez besoin d'utiliser le
await
mot clé explicitement.Nous inventons un attribut:
[AutoAwait]
. Cela ne peut être appliqué qu'aux méthodes. Une façon de l'appliquer à votre méthode consiste à la marquerasync
. Mais vous pouvez également le faire à la main, par exemple:Ensuite, à l'intérieur de n'importe quelle
async
méthode, le compilateur supposera que vous voulez attendre un appel àDownloadDocumentAsync
, vous n'avez donc pas besoin de le spécifier. Tout appel à cette méthode l'attendra automatiquement.Maintenant, si vous voulez "devenir intelligent" et obtenir le
Task<Document>
, vous utilisez un opérateurstart
, qui ne peut apparaître qu'avant un appel de méthode:Bien, je pense. Maintenant, un appel de méthode simple signifie ce qu'il signifie généralement: attendez que la méthode soit terminée. Et
start
indique quelque chose de différent: n'attendez pas.Pour le code qui apparaît en dehors d'une
async
méthode, la seule façon dont vous êtes autorisé à appeler une[AutoAwait]
méthode est de la préfixer avecstart
. Cela vous oblige à écrire du code qui a la même signification, qu'il apparaisseasync
ou non dans une méthode.Ensuite, je commence à devenir gourmand! :)
Tout d'abord, je souhaite
async
appliquer aux méthodes d'interface:Cela signifie essentiellement que la méthode d'implémentation doit retourner
Task<int>
ou quelque chose de compatible avecawait
, et les appelants à la méthode obtiendront un[AutoAwait]
comportement.De plus, lorsque j'implémente la méthode ci-dessus, je veux pouvoir écrire:
Je n'ai donc pas à mentionner
Task<int>
comme type de retour.De plus, je veux
async
m'appliquer aux types de délégués (qui, après tout, sont comme des interfaces avec une méthode). Donc:Un
async
délégué a - vous l'aurez deviné - un[AutoAwait]
comportement. À partir d'uneasync
méthode, vous pouvez l'appeler et elle sera automatiquementawait
éditée (à moins que vous ne choisissiez de la justestart
). Et donc si vous dites:Ça marche. Ce n'est pas un appel de méthode. Aucune tâche n'a encore été lancée - une
async delegate
n'est pas une tâche. C'est une usine pour faire des tâches. Tu peux dire:Et cela va démarrer une tâche et attendre qu'elle se termine et vous donner le résultat. Ou vous pouvez dire:
Donc, un endroit dans ce domaine où la "plomberie" fuit est que si vous voulez faire un délégué à une
async
méthode, vous devez savoir utiliser unasync delegate
type. Donc au lieu deFunc
vous devez direAsyncFunc
, et ainsi de suite. Bien qu'un jour ce genre de chose pourrait être corrigé par une inférence de type améliorée.Une autre question est de savoir ce qui devrait arriver si vous dites commencer par une méthode ordinaire (non asynchrone). De toute évidence, une erreur de compilation serait l'option sûre. Mais il y a d'autres possibilités.
la source
var
, potentiellement devoir remplacer un nom de type long et explicite, et est également ambigu entre leawait
cas et le cas où quelqu'un a accidentellement appelé la méthode async au lieu de la méthode synchrone normale. Cela semble intuitif au premier abord mais viole en fait le principe de la moindre surprise.var
? Je me demande si vous répondez à la révision précédente de ma réponse ... Je l'ai complètement réécrite. Vous pouvez maintenant penser à cette suggestion comme suit: si la méthode est marquée avec un attribut spécial, c'est comme si leawait
mot-clé était automatiquement inséré devant les appels à cette méthode (à moins que vous ne le supprimiez avec lestart
préfixe). Tout reste exactement comme dans le CTP, etvar
fonctionne donc très bien.public async Task<int> FooAsync()
.(si vous ne l'obtenez pas, lisez l' entrée de blog d'Eric . Au moins c'est mieux que
for sooth Romeo wherefore art thou AsyncFetch(…)
)la source
Je pense que ça
async
va, mais c'est peut-être parce que je l'associe aux pages asynchrones ASP.NET - même idée.Pour le
await
mot - clé que je préfèrecontinue after
ouresume after
.Je ne suis pas comme
yield
ou l' une de ses variantes, parce que la sémantique sont telles que la méthode peut donner jamais réellement l' exécution; cela dépend de l'état de la tâche.la source
resume after
pourawait
. Peutasync
-être qu'on pourrait l'appelerresumable
.after
, l'continue after
approche a un fort avantage d'implémentation: elle inclut un mot-clé contextuel existant, mais avec une syntaxe qui n'est pas compatible avec l'utilisation actuelle. Cela garantit que l'ajout ne cassera jamais le code existant. Lorsque vous utilisez un mot clé entièrement nouveau, l'implémentation doit faire face aux utilisations possibles du mot comme identifiant sur un code plus ancien, ce qui peut devenir assez délicat.J'ai également ajouté des commentaires sur le blog d'Eric, je ne vois aucun problème avec l'utilisation du même mot clé
async
J'exprime juste que je veux télécharger le fichier de manière asynchrone. Il y a un peu de redondance ici, "async" apparaît deux fois, car c'est aussi dans le nom de la méthode. Le compilateur pourrait être très intelligent et détecter la convention selon laquelle les méthodes se terminant par "Async" sont en fait des méthodes async, et ajouter cela pour nous dans le code compilé. Au lieu de cela, vous voudrez peut-être juste appeler
au lieu d'appeler le synchrone
Heck, nous devrions également être en mesure de les définir de la même manière, puisque le mot-clé async est là dans notre déclaration, pourquoi devons-nous ajouter manuellement "Async" à chaque nom de méthode - le compilateur peut le faire pour nous.
la source
async
mot - clé sur la méthode est juste une subtilité (si j'ai bien compris), je me demande si la meilleure chose ne serait pas de faire le contraire de ce que vous proposez: abandonner leasync
sur la méthode, et simplement l'utiliser où ils ont actuellementawait
.async Task<Byte[]> DownloadFile(...)
plutôt queTask<Byte[]> DownloadFileAsync(...)
(Ce dernier sera de toute façon la signature compilée). De toute façon ça marche.async = task - Il s'agit de modifier une fonction pour renvoyer une tâche, alors pourquoi ne pas utiliser le mot-clé "task"?
wait = finish - Nous n'avons pas nécessairement besoin d'attendre, mais la tâche doit "terminer" avant d'utiliser le résultat.
la source
J'aime
yield until
.yield while
, déjà suggéré, est génial et n'introduit pas de nouveaux mots clés, mais je pense que "jusqu'à" capture un peu mieux le comportement.Je pense que
yield <something>
c'est une excellente idée, car le rendement capture déjà l'idée de faire si bien le reste de la méthode. Peut-être que quelqu'un peut penser à un meilleur mot que «jusqu'à».la source
Je veux simplement enregistrer mon vote pour la suggestion d'Aaron G
comefrom
- la première utilisation appropriée que j'ai vue de la déclaration COMCFROM d'INTERCAL . L'idée est que c'est en quelque sorte l'opposé de GOTO (sauter de l'instruction GOTO) en ce sens qu'il fait de la place dans votre code pour passer à l'instruction COMEFROM.la source
Puisque nous avons affaire à
Task<T>
s, que diriez-vous d'utiliserstart
comme mot-clé précédant l'instruction, comme dans:start var document = FetchAsync(urls[i]);
la source
finish
serait peut -être encore mieux questart
?Il est à noter que F # utilise également le
async
mot clé dans ses flux de travail asynchrones, ce qui est à peu près la même chose que la nouvelle fonctionnalité asynchrone en C # 5. Par conséquent, je garderais celui-là mêmePour le
await
mot clé en F #, ils utilisent simplementlet!
au lieu delet
. C # n'a pas la même syntaxe d'affectation, ils ont donc besoin de quelque chose sur le côté droit du=
signe. Comme l'a dit Benjol, il fonctionne de la même manièreyield
que ce devrait donc être presque une variante de cela.la source
do!
, mais vous le saviez ...yield async FetchAsync(..)
Cela va parfaitement avec le
async
modificateur que vous devez appliquer à la méthode que vous invoquez. Et aussi la sémantique du courantyield return
qui est, vous revenez et donne l'exécution au code énumérateur tandis que dans ce cas, vous cédez votre exécution à la méthode asynchrone.Imaginez si à l'avenir il y aurait d'autres utilisations
yield
, nous pourrions ajouter unyield x
où x est la nouvelle fonctionnalité brillante au lieu d'avoir tous ces mots clés différents pour faire la plupart du temps la même chose, donner l'exécution.Franchement, je ne comprends pas très bien l'argument «ne pas céder l'exécution». Après tout, l'intérêt d'appeler une autre méthode n'est-il pas déjà de «céder l'exécution» à cette méthode? Qu'il soit asynchrone ou non? Je manque quelque chose ici?
Et bon pour vous si le
async
retourne de manière synchrone mais en ayant le mot-clé là, cela signifie qu'il y a une chance probable que la méthode s'exécute de manière asynchrone et que vous céderez l'exécution à une autre méthode. Votre méthode doit en tenir compte, qu'elle effectue ou non des appels asynchrones.OMI Je pense que les différents cas «sans céder» sont un détail de mise en œuvre. Je préfère garantir la cohérence de la langue (c'est-à-dire la réutilisation
yield
).la source
Que diriez-vous
complete
, comme dans "Je veux que la tâche soit terminée"?la source
task
(pour la déclaration de méthode) etasync
(dans le corps de la méthode)la source