asincrono e attendi - sondaggio per alternative [chiuso]

14

Ora che sappiamo cosa c'è in serbo per il c # 5, apparentemente c'è ancora un'apertura per influenzare la scelta delle due nuove parole chiave per " Asynchrony " che sono stati annunciati ieri da Anders Heijsberg su 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 ha una spiegazione della scelta delle attuali due parole chiave e del modo in cui sono state fraintese negli studi di usabilità. I commenti hanno diverse altre proposizioni.

Per favore, un suggerimento per risposta, i duplicati saranno cancellati.

    
posta Benjol 29.10.2010 - 22:35
fonte

13 risposte

6

Dato che non sono chiaro sul significato / necessità di async , non posso davvero discuterne, ma il mio miglior suggerimento per sostituire await è:

yield while (guarda! nessuna nuova parola chiave)

Nota avendoci pensato un po 'di più, mi chiedo se riutilizzare while in questo modo sia una buona idea - la tendenza naturale sarebbe quella di aspettarsi un booleano in seguito.

(Pensa: trovare buone parole chiave è come trovare dei buoni nomi di dominio:)

    
risposta data 29.10.2010 - 22:41
fonte
5

Che ne dici di non avere una parola chiave?

Vorrei che il compilatore rendesse conto che, il più delle volte, quando chiamo un metodo asincrono, voglio il risultato.

Document doc = DownloadDocumentAsync();

Questo è tutto. Il motivo per cui le persone hanno difficoltà a pensare a una parola chiave per questa cosa è perché è come avere una parola chiave per "fai la cosa che faresti se le cose fossero perfettamente normali". Questo dovrebbe essere il valore predefinito, non richiedere una parola chiave.

Aggiorna

Inizialmente avevo suggerito che il compilatore dovesse diventare intelligente con l'inferenza di tipo per capire cosa fare. Pensandoci meglio, manterrò l'implementazione esistente nel CTP così com'è, ma apporterò un paio di aggiunte banali, in modo da ridurre i casi in cui è necessario utilizzare esplicitamente la parola chiave await .

Inventiamo un attributo: [AutoAwait] . Questo può essere applicato solo ai metodi. Un modo per farlo applicare al tuo metodo è contrassegnarlo async . Ma potresti anche farlo a mano, ad esempio:

[AutoAwait]
public Task<Document> DownloadDocumentAsync()

Quindi, all'interno di qualsiasi metodo async , il compilatore supporrà che desideri attendere su una chiamata a DownloadDocumentAsync , quindi non devi specificarlo. Qualsiasi chiamata a tale metodo la attenderà automaticamente.

Document doc = DownloadDocumentAsync();

Ora, se vuoi "diventare furbo" e ottenere Task<Document> , usi un operatore start , che può comparire solo prima di una chiamata al metodo:

Task<Document> task = start DownloadDocumentAsync();

Neat, penso. Ora una semplice chiamata di metodo significa cosa significa in genere: attendere il completamento del metodo. E start indica qualcosa di diverso: non aspettare.

Per il codice visualizzato al di fuori di un metodo async , l'unico modo in cui ti è consentito chiamare un metodo [AutoAwait] è precedendolo con start . Questo ti costringe a scrivere codice che ha lo stesso significato indipendentemente dal fatto che appaia in un metodo async o meno.

Allora inizio ad essere avido! :)

In primo luogo, voglio async da applicare ai metodi di interfaccia:

interface IThing
{
    async int GetCount();
} 

In pratica significa che il metodo di implementazione deve restituire Task<int> o qualcosa compatibile con await , e chi chiama al metodo otterrà il comportamento di [AutoAwait] .

Anche quando implemento il metodo sopra, voglio poter scrivere:

async int GetCount()

Quindi non devo menzionare Task<int> come tipo di ritorno.

Inoltre, voglio async da applicare a tipi di delegati (che, dopotutto, sono come interfacce con un metodo). Quindi:

public async delegate TResult AsyncFunc<TResult>();

Un async delegato ha - hai indovinato - [AutoAwait] comportamento. Da un metodo async puoi chiamarlo e sarà automaticamente await ed (a meno che tu non scelga solo start ). E quindi se dici:

AsyncFunc<Document> getDoc = DownloadDocumentAsync;

Questo funziona. Non è una chiamata al metodo. Nessuna attività è stata ancora avviata: una async delegate non è un'attività. È una fabbrica per fare compiti. Puoi dire:

Document doc = getDoc();

E ciò avvierà un'attività e attenderà che finisca e ti dia il risultato. Oppure puoi dire:

Task<Document> t = start getDoc();

Quindi, un punto in cui è presente "l'impianto idraulico" è che se si desidera eseguire un delegato su un metodo async , è necessario conoscere un tipo async delegate . Quindi, invece di Func devi dire AsyncFunc , e così via. Anche se un giorno quel genere di cose potrebbe essere corretto migliorando l'inferenza del tipo.

Un'altra domanda è cosa dovrebbe succedere se dici di iniziare con un metodo ordinario (non asincrono). Ovviamente un errore di compilazione sarebbe l'opzione sicura. Ma ci sono altre possibilità.

    
risposta data 30.10.2010 - 19:30
fonte
4
hearken unto AsyncFetch(…)

(se non lo capisci, leggi Eric post di blog . Almeno è meglio di for sooth Romeo wherefore art thou AsyncFetch(…) )

    
risposta data 29.10.2010 - 23:04
fonte
4

Penso che async stia bene, ma forse è perché lo associo alle pagine asincrone di ASP.NET - stessa idea.

Per la parola chiave await preferisco continue after o resume after .

I non come yield o una delle sue varianti, perché la semantica è tale che il metodo potrebbe non fornire mai effettivamente l'esecuzione; dipende dallo stato del compito.

    
risposta data 29.10.2010 - 23:16
fonte
3

Ho aggiunto anche commenti sul blog di Eric, non vedo alcun problema con l'utilizzo della stessa parola chiave async

var data = async DownloadFileAsync(url);

Sto solo esprimendo che voglio scaricare il file in modo asincrono. C'è un po 'di ridondanza qui, "async" appare due volte, perché è anche nel nome del metodo. Il compilatore potrebbe essere più intelligente e rilevare la convenzione secondo cui i metodi che terminano in "Async" sono infatti metodi asincroni, e aggiungono quello per noi nel codice compilato. Quindi, invece, potresti semplicemente voler chiamare

var data = async DownloadFile(url);

al contrario di chiamare quello sincrono

var data = DownloadFile(url);

Diamine, dovremmo anche essere in grado di definirli allo stesso modo, dato che la parola chiave async è presente nella nostra dichiarazione, perché dobbiamo aggiungere manualmente "Async" a ciascun nome di metodo - il compilatore può farlo per noi.

    
risposta data 30.10.2010 - 02:00
fonte
3

async = task - Modifica una funzione per restituire un'attività, quindi perché non utilizzare la parola chiave "task"?

await = finish - Non è necessario necessariamente attendere, ma l'attività deve "finire" prima di utilizzare il risultato.

    
risposta data 07.11.2010 - 03:28
fonte
2

Mi piace yield until . yield while , già suggerito, è ottimo e non introduce nuove parole chiave, ma penso che "until" acquisisca un po 'meglio il comportamento.

Penso che yield <something> sia una grande idea, perché yield coglie già l'idea di rendere il resto del metodo una continuazione così bene. Forse qualcuno può pensare ad una parola migliore di "until."

    
risposta data 30.10.2010 - 02:23
fonte
2

Voglio solo registrare il mio voto per il suggerimento di Aaron G di comefrom - il primo uso appropriato che ho visto di INTERCAL COMEFROM dichiarazione. L'idea è che è un po 'l'opposto di GOTO (saltando via da l'istruzione GOTO) in quanto fa un po' di posto nel tuo codice per passare a l'istruzione COMEFROM.

    
risposta data 30.10.2010 - 07:09
fonte
2

Poiché abbiamo a che fare con Task<T> s, che ne dici di utilizzare start come parola chiave precedente l'istruzione, come in:

start var document = FetchAsync(urls[i]);

    
risposta data 05.11.2010 - 19:22
fonte
1

Vale la pena notare che F # usa anche la parola chiave async nei suoi flussi di lavoro asincroni, che è praticamente la stessa cosa della nuova funzionalità asincrona in C # 5. Pertanto, manterrei quello stesso lo stesso

Per la parola chiave await in F #, usano solo let! anziché let . C # non ha la stessa sintassi di assegnazione, quindi hanno bisogno di qualcosa sul lato destro del segno = . Come ha detto Benjol, funziona allo stesso modo di yield quindi dovrebbe quasi essere una variante di quello.

    
risposta data 30.10.2010 - 01:50
fonte
1

yield async FetchAsync(..)

Ciò si sposa perfettamente con il modificatore async che devi mettere sul metodo che stai invocando. E anche la semantica del corrente yield return cioè, si restituisce e produce l'esecuzione al codice di enumerazione mentre in questo caso si sta cedendo l'esecuzione al metodo asincrono.

Immagina se in futuro ci saranno altri usi per yield , potremmo aggiungere un yield x dove x è la nuova caratteristica brillante invece di avere tutte queste parole chiave diverse per fare la stessa cosa, eseguire l'esecuzione.

Francamente, non capisco l'argomento "non cedere all'esecuzione". Dopotutto, non è forse il momento di chiamare un altro metodo per "dare esecuzione" a quel metodo? Indipendentemente dal fatto che sia asincrono o no? Mi sto perdendo qualcosa qui?

E fa bene a te se async viene restituito in modo sincrono, ma se la parola chiave deve indicare che c'è una probabile possibilità che il metodo venga eseguito in modo asincrono e che tu stia cedendo l'esecuzione a un altro metodo. Il tuo metodo deve tener conto di ciò indipendentemente dal fatto che il metodo esegua effettivamente chiamate asincrone o meno.

IMO Penso che i vari casi "non produttivi" siano un dettaglio di implementazione. Preferisco garantire la coerenza nella lingua (cioè riutilizzando yield ).

    
risposta data 31.10.2010 - 20:11
fonte
0

Che ne dici di complete , come in "Voglio che l'attività sia completata"?

Task<byte[]> downloadTask = DownloadFileAsync(url);
byte[] data = complete downloadTask;
    
risposta data 30.10.2010 - 01:50
fonte
0

task (per la dichiarazione del metodo) e async (all'interno del corpo del metodo)

    
risposta data 24.01.2012 - 05:08
fonte

Leggi altre domande sui tag