Dernièrement, je n'arrive pas à en avoir assez de l'incroyable motif asynchrone de C # 5.0. Où étais-tu, durant toute ma vie?
Je suis absolument ravi de la syntaxe simple, mais j'ai une petite difficulté. Mon problème est que les fonctions asynchrones ont une déclaration totalement différente des fonctions régulières. Étant donné que seules les fonctions asynchrones peuvent attendre sur d'autres fonctions asynchrones, lorsque j'essaie de porter un ancien code de blocage vers async, j'ai un effet domino des fonctions que je dois convertir.
Les gens ont appelé cela une infestation de zombies . Lorsque async obtient une morsure dans votre code, il ne cesse de s'agrandir. Le processus de portage n'est pas difficile, il suffit de jeter async
la déclaration et d'envelopper la valeur de retour avec Task<>
. Mais il est ennuyeux de le faire encore et encore lors du portage de l'ancien code synchrone.
Il me semble que ce sera beaucoup plus naturel si les deux types de fonctions (async et plain old sync) avaient exactement la même syntaxe. Si tel était le cas, le portage ne demanderait aucun effort et je pourrais basculer sans douleur entre les deux formes.
Je pense que cela pourrait fonctionner si nous suivons ces règles:
Les fonctions asynchrones ne nécessiteront plus la
async
déclaration. Leurs types de retour n'auraient pas à être enveloppésTask<>
. Le compilateur identifiera lui-même une fonction asynchrone pendant la compilation et effectuera automatiquement l'enveloppement de la tâche <> selon les besoins.Plus besoin de tirer et d'oublier les fonctions asynchrones. Si vous souhaitez appeler une fonction asynchrone, vous devrez l'attendre. J'utilise à peine le feu et oublie de toute façon, et tous les exemples de conditions de course folles ou de blocages semblent toujours être basés sur eux. Je pense qu'ils sont trop confus et «déconnectés» de l'état d'esprit synchrone que nous essayons de tirer parti.
Si vous ne pouvez vraiment pas vivre sans tirer et oublier, il y aura une syntaxe spéciale pour cela. En tout cas, cela ne fera pas partie de la simple syntaxe unifiée dont je parle.
Le seul mot-clé dont vous avez besoin pour désigner un appel asynchrone est
await
. Si vous avez attendu, l'appel est asynchrone. Si vous ne le faites pas, l'appel est tout simplement synchrone (rappelez-vous, nous n'avons plus le feu et oublions).Le compilateur identifiera automatiquement les fonctions asynchrones (car elles n'ont plus de déclaration spéciale). La règle 4 rend cela très simple à faire - si une fonction a un
await
appel à l'intérieur, c'est async.
Cela pourrait-il fonctionner? ou est-ce que je manque quelque chose? Cette syntaxe unifiée est beaucoup plus fluide et pourrait résoudre complètement l'infestation de zombies.
Quelques exemples:
// assume this is an async function (has await calls inside)
int CalcRemoteBalanceAsync() { ... }
// assume this is a regular sync function (has no await calls inside)
int CalcRemoteBalance() { ... }
// now let's try all combinations and see what they do:
// this is the common synchronous case - it will block
int b1 = CalcRemoteBalance();
// this is the common asynchronous case - it will not block
int b2 = await CalcRemoteBalanceAsync();
// choosing to call an asynchronous function in a synchronous manner - it will block
// this syntax was used previously for async fire-and-forget, but now it's just synchronous
int b3 = CalcRemoteBalanceAsync();
// strange combination - it will block since it's calling a synchronous function
// it should probably show a compilation warning though
int b4 = await CalcRemoteBalance();
Remarque: il s'agit d'une continuation d'une discussion connexe intéressante dans SO
la source
await
immédiatement. Vous pouvez faire quelque chose comme çavar task = FooAsync(); Bar(); await task;
. Comment pourrais-je procéder dans votre proposition?async
. Je pense que c'est l'un des grands avantages deasync
-await
: qu'il vous permet de composer facilement des opérations asynchrones (et pas seulement de la manière la plus simple "démarrer A, attendre A, démarrer B, attendre B"). Et il existe déjà une syntaxe spéciale à cet effet: elle s'appelleawait
.Réponses:
Vous avez déjà répondu à votre question dans la question SO que vous avez liée.
Lorsque WinRT est sorti pour la première fois, les concepteurs décrivaient comment ils décidaient quelles opérations allaient être asynchrones. Ils ont décidé que tout ce qui allait prendre 50 ms ou plus serait asynchrone, et le reste des méthodes serait des méthodes ordinaires, non asynchrones.
Combien de méthodes ont dû être réécrites pour les rendre asynchrones? Environ 10% d'entre eux. Les 90% restants n'ont pas été affectés du tout.
Eric Lippert poursuit en expliquant dans des détails techniques assez substantiels pourquoi ils ont choisi de ne pas adopter une approche unique. Il dit essentiellement que
async
etawait
sont une implémentation partielle du style de passage de continuation, et que l'optimisation d'un tel style pour s'adapter à tous les cas est un problème difficile.la source
async
produirait des infestations de zombies. Même si une méthode appelle 10 autres méthodes, ne vous contentez-vous pas deasync
celle de niveau supérieur?