Problema con pattern asincrono / attesa - in C # e JavaScript - come restituire il valore di sincronizzazione

1

Nel vecchio stile NodeJS atteso, quando si chiama una funzione che ha un aspetto asincrono, si passa al noto callback che viene chiamato quando viene eseguita la parte asincrona. Questo non ha inquinato il valore di ritorno della funzione mentre la funzione può ancora restituire qualcosa di significativo al chiamante in modo sincrono.

Il problema con lo schema async / await ora è che per usarlo, devi decidere se una funzione è sincrona o asincrona. Ciò significa che se ho una funzione esistente che è sincrona e ha un valore di ritorno che verrà calcolato in modo sincrono e quindi restituito quando la funzione ritorna, e voglio aggiungere un componente asincrono, in precedenza aggiungerei una richiamata e cambiare i chiamanti. Ma ora devo rendere il valore restituito il valore asincrono e il valore di ritorno originale --- trovare un altro modo. Quale sarebbe?

Utilizzeresti un parametro 'out' in C #? Non è una buona pratica. Vuoi passare in un oggetto il cui stato si modifica per restituire il valore di sincronizzazione?

La tendenza attuale è restituire una tupla e un oggetto con più valori. Ma uno di questi valori può essere sincrono e l'altro asincrono?

    
posta Daisha Lynn 04.08.2018 - 03:47
fonte

4 risposte

2

Perché non puoi restituire un'attività già completata?

C #: return Task.FromResult(...);

JavaScript: return Promise.resolve(...);

Infatti, C # ha aggiunto recentemente ValueTask<T> per evitare allocazioni per questo scenario in cui un valore è immediatamente disponibile.

    
risposta data 09.08.2018 - 07:35
fonte
0

The current trend is return a tuple, and object with multiple values. But can one of those values by synchronous and the other asynchronous?

sicuramente puoi restituirlo. %codice%. Puoi crearlo in questo modo:

// this is a function starting a task producing Bar
Task<Bar> GetBarAsync() {
    ...
}

...

Tuple<Foo, Task<Bar>> Baz()
{
    return Tuple.Create(
        new Foo(),
        GetBarAsync());
}

Tuttavia, poiché questo è SE, vorrei aggiungere che non capisco chiaramente perché avresti bisogno di tale funzione. Mi mescola chiaramente le preoccupazioni. La funzione asincrona non significa fare nulla al momento della chiamata. Fa qualcosa, in effetti, ma non importa in uno scenario tipico.

    
risposta data 04.08.2018 - 06:33
fonte
0

Perché vorresti questo? Attenendosi al tuo esempio con Book e Footnotes , dove uno viene prelevato in modo sincrono e l'altro viene prelevato in modo asincrono, dovrebbero essere in realtà due metodi (o almeno due chiamate al metodo), anziché uno, poiché il recupero Book synchrnously e il recupero di Book con note a piè di pagina in modo asincrono sono due cose leggermente diverse.

Dal tuo commento all'altra risposta:

But for a client that does care, he wants to wait for the task to complete. How to return the task to the caller as well as the book.

Potresti aggiungere un parametro per specificare che vuoi recuperare. Solo i metadati (per la tua domanda supponiamo che i metadati vengano restituiti rapidamente) o dati estesi (che non verranno restituiti così rapidamente)

public Book FetchBook(FetchBookOptions options);
public Task<Book> FetchBookAsync(FetchBookOptions options);

[Flags]
public enum FetchBookOptions
{
    None,
    Metadata = 1,
    Content = 2,
    Footnotes = 4,
    All = Metadata | Content | Footnotes
}

Il cliente che si prende cura dei metadati, delle note a piè di pagina e dei contenuti, ma deve rimanere reattivo, può chiamare

var book = await bookRepository.FetchBookAsync(FetchBookOptions.All);

Il client che non rende disponibile async/await , ma ha bisogno che tutti i dati possano chiamare

 var book = await bookRepository.FetchBookAsync(FetchBookOptions.All);

e il client che ha bisogno solo dei metadati, che è noto per essere fornito "immediatamente" può chiamare

var book = await bookRepository.FetchBookAsync(FetchBookOptions.Metadata);

o

var book = await bookRepository.FetchBookAsync(FetchBookOptions.Metadata);

Alla fine puoi fare qualcosa del genere

private async void Button_OnClick()
{
    this.SetBooks(await bookRepository.FetchBookAsync(FetchBookOptions.Metadata));
    this.UpdateBooksFootnotes(await bookRepository.FetchBooksAsync(FetchBookOptions.All));
}

Ciò consente di ottenere esattamente ciò che desideri, impostando immediatamente i libri originali - dato che FetchBookOptions.Metadata restituisce immediatamente, o almeno molto rapidamente - e non appena le note a piè di pagina sono state recuperate, puoi aggiornarle.

    
risposta data 09.08.2018 - 10:19
fonte
0

The current trend is return a tuple, and object with multiple values. But can one of those values by synchronous and the other asynchronous?

Sì, semplicemente Tuple<Foo, Task<Bar>> .

Ma forse non lo vuoi. Invece, restituisci entrambi in modo asincrono.

async Task<Tuple<Foo, Bar>> getFooBarAsync()
{
    var bar = getBarAsync();
    var foo = getFoo();
    return new Tuple<Foo, Bar>(foo, await bar);
}
    
risposta data 09.08.2018 - 11:53
fonte

Leggi altre domande sui tag