Mixing di programmazione reattiva con requisiti di ritorno non reattivi

1

Contesto variabile da un chiamante iniziale non reattivo

L'intera applicazione non può essere reattiva, cioè questo metodo deve restituire un risultato qui

public string GetTextOfInterest()
{           
    var searchQuery = "Single Responsibility";
    var titleShouldContain = "SRP";
    var uriShouldContain = "pattern";
    var pageShouldContain = "arguments";
    return this.NonReactive(searchQuery, titleShouldContain, uriShouldContain,pageShouldContain);
}

Implementazione del blocco non reattivo

Questa implementazione non reattiva funziona bene

private string NonReactive(string searchQuery, string titleShouldContain, string uriShouldContain, string pageShouldContain)
{
    // Googler returns result directly here and does not move on before          
    var gooResult = this.googler.Search(searchQuery);
    if (gooResult.Title.Contains(titleShouldContain) && gooResult.Uri.Contains(uriShouldContain))
    {
        // Blocking here again to wait for this result
        var scrResult = this.scraper.Scrape(gooResult.Uri);
        if (scrResult.Body.Contains(pageShouldContain))
        {
            // Blocking up to this point ensures sequential execution and ability to return this final result
            return scrResult.Body;
        }
    }
    return null;
}

Come rispondere in modo reattivo?

Questa implementazione reattiva non funziona

private string ReactiveButUseless(string searchQuery, string titleShouldContain, string uriShouldContain, string pageShouldContain)
{            
    googler.Stream.Subscribe(
        gooResult =>
            {
                if (gooResult.Title.Contains(titleShouldContain) && gooResult.Uri.Contains(uriShouldContain))
                {
                    scraper.Stream.Subscribe(
                        scrResult =>
                            {
                                if (scrResult.Body.Contains(pageShouldContain))
                                {
                                    // Get final result here, but no good as method has already returned (null)
                                    var finalResult = scrResult.Body;
                                }
                            });
                    scraper.Scrape(gooResult.Uri);                            
                }
            });      
    googler.Search(searchQuery);            
    return null;
}

Esiste un modo per implementare una soluzione reattiva di lavoro?

  • senza dover modificare l'implementazione di Google e Raschiamento perché devono rimanere puliti e riutilizzabili per altri scopi (altrimenti potrebbero passare in delegati)
  • e senza bloccare? Potrebbe aspettare il risultato del flusso e del blocco, ma in questo caso non è meglio dell'implementazione del blocco non reattivo? O semplicemente non è possibile mescolare stili reattivi e non reattivi senza bloccare?
posta Cel 11.06.2015 - 11:26
fonte

1 risposta

1

La risposta breve è no.

Le due cose che vuoi si escludono a vicenda, non puoi continuare un blocco di codice mentre aspetti una risposta da un server asincrono e in qualche modo garantisci di recuperarlo prima che il blocco di codice ritorni (ad eccezione di async / await [vedi sotto ]).

Detto questo, se vuoi usare Reactive, ci sono un paio di approcci da provare:

Prima alcuni ripulisci:

    private IObservable<string> GetScrapeStream(Uri resultUri, string pageShouldContain)
    {
        return Observable.Create<string>(observer =>
        {
            var subscription =
                scraper.Stream
                .Where(result => result.Body.Contains(pageShouldContain))
                .Select(result => result.Body)
                .Subscribe(observer);

            scraper.Scrape(resultUri);
            return subscription;
        });
    }

    private IObservable<string> GetGoogleStream(string searchQuery, 
                                                string titleShouldContain, 
                                                string uriShouldContain, 
                                                string pageShouldContain)
    {
        return Observable.Create<string>(observer =>
        {
            var subscription =
                googler.Stream
                .Where(result => result.Title.Contains(titleShouldContain) &&
                                 result.Uri.Contains(uriShouldContain))
                .SelectMany(result =>
                {
                    return GetScrapeStream(result.Uri, pageShouldContain);
                })
                .Subscribe(observer);

            googler.Search(searchQuery);
            return subscription;
        });
    }

Da quando ho già detto che non puoi avere la tua torta e mangiarla, hai due opzioni:

//This will block, and Last() is actually deprecated, so it will probably be going away
private string ReactiveButBlocking(string searchQuery, 
                                   string titleShouldContain, 
                                   string uriShouldContain, 
                                   string pageShouldContain)
{
  return GetGoogleStream(searchQuery, titleShouldContain, uriShouldContain, pageShouldContain)
         .Last();
}

Se hai almeno .Net 4.5 hai anche async / await a tua disposizione, che sono supportati molto bene in Rx, tuttavia, la tua firma del metodo cambierà leggermente, e nel metodo del chiamante dovrai fare string result = await ReactiveAndAsync(...); Realizza però che questo non è il tuo blocco standard, perché in realtà libera il thread finché il metodo non restituisce un valore.

vedi riferimento

private async Task<string> ReactiveAndAsync(string searchQuery, 
                                  string titleShouldContain, 
                                  string uriShouldContain, 
                                  string pageShouldContain)
{
  return await GetGoogleStream(searchQuery, titleShouldContain, uriShouldContain, pageShouldContain);
}

tl; dr

Rx non fa nulla di magico, non sconfiggerà la causalità e non è perfetto per ogni caso d'uso, almeno fino al 3.0. Tuttavia, ti consentirà di creare stream logici che, auspicabilmente, miglioreranno la leggibilità, l'estensibilità e una separazione dei problemi.

    
risposta data 11.06.2015 - 21:42
fonte

Leggi altre domande sui tag