Sfoca le linee tra funzioni asincrone e regolari in C # 5.0

8

Ultimamente non riesco a ottenere abbastanza del sorprendente async-await modello di C # 5.0. Dove sei stata tutta la mia vita?

Sono assolutamente entusiasta della semplice sintassi, ma sto riscontrando una piccola difficoltà. Il mio problema è che le funzioni asincrone hanno una dichiarazione totalmente diversa dalle normali funzioni. Poiché solo le funzioni asincrone possono attendere su altre funzioni asincrone, quando sto provando a portare un vecchio codice di blocco su async, sto avendo un effetto domino di funzioni che devo convertire.

Le persone si sono riferite a questa come infestazione zombi . Quando async prende un morso nel tuo codice, continuerà a diventare sempre più grande. Il processo di porting non è difficile, è solo il lancio di async nella dichiarazione e il ritorno del valore di ritorno con Task<> . Ma è fastidioso farlo più e più volte durante il porting del vecchio codice sincrono.

Mi sembra molto più naturale se entrambi i tipi di funzione (sincrona asincrona e semplice) abbiano la stessa sintassi esatta. In questo caso, il porting richiederà uno sforzo zero e potrei passare senza problemi tra le due forme.

Penso che questo potrebbe funzionare se seguiamo queste regole:

  1. Le funzioni asincrone non richiedono più la dichiarazione async . I loro tipi di ritorno non dovrebbero essere racchiusi in Task<> . Il compilatore identificherà una funzione asincrona durante la compilazione da solo ed eseguirà l'operazione < > riavvolgimento automatico in base alle esigenze.

  2. Niente più chiamate ignote alle funzioni asincrone. Se si desidera chiamare una funzione asincrona, è necessario attendere su di essa. Uso a malapena il fuoco e lo dimentico comunque, e tutti gli esempi di pazze condizioni di gara o di situazioni di stallo sembrano sempre basate su di loro. Penso che siano troppo confusi e "fuori controllo" con la mentalità sincrona che cerchiamo di sfruttare.

  3. Se davvero non puoi vivere senza fire-and-forget, ci sarà una sintassi speciale per questo. In ogni caso, non farà parte della semplice sintassi unificata di cui sto parlando.

  4. L'unica parola chiave che devi indicare una chiamata asincrona è await . Se hai atteso, la chiamata è asincrona. Se non lo fai, la chiamata è semplice sincrona (ricorda, non abbiamo più fire-and-forget).

  5. Il compilatore identificherà automaticamente le funzioni asincrone (dato che non hanno più una dichiarazione speciale). La regola 4 rende questo molto semplice da fare - se una funzione ha una chiamata await all'interno, è asincrona.

Potrebbe funzionare? Oppure mi sfugge qualcosa? Questa sintassi unificata è molto più fluida e potrebbe risolvere completamente l'infestazione di zombi.

Alcuni esempi:

// 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();

Nota: questa è la continuazione di un'interessante discussione correlata in SO

    
posta talkol 29.08.2013 - 22:56
fonte

1 risposta

8

La tua domanda ha già una risposta nella domanda SO che hai collegato.

The purpose of async/await is to make it easier to write code in a world with many high latency operations. The vast majority of your operations are not high latency.

Quando è stato pubblicato WinRT , i progettisti hanno descritto come hanno deciso quali operazioni sarebbero state asincrone. Decisero che qualsiasi cosa avrebbe richiesto 50 ms o più sarebbe asincrona, e il resto dei metodi sarebbero metodi ordinari, non asincroni.

Quanti dei metodi dovevano essere riscritti per renderli asincroni? Circa il 10 percento di loro. L'altro 90% non è stato influenzato affatto.

Eric Lippert continua spiegando con dettagli tecnici abbastanza sostanziali perché hanno scelto di non adottare un approccio valido per tutti. Sostanzialmente afferma che async e await sono un'implementazione parziale dello stile di passaggio continuo e che l'ottimizzazione di uno stile simile per tutti i casi è un problema difficile.

    
risposta data 30.08.2013 - 01:02
fonte

Leggi altre domande sui tag