如何将两个异步操作与Reactive Framework链接在一起?

时间:2010-02-27 00:06:06

标签: .net asynchronous system.reactive

我真正想做的就是完成两个异步操作,一个接一个。 E.g。

下载网站X.完成后,下载网站Y。

3 个答案:

答案 0 :(得分:2)

从两个observable中执行SelectMany(使用ToAsync将操作作为IObservables),就像LINQ选择多个(或使用语法糖):

var result = 
from x in X
from y in Y
select new { x, y }  

还有其他选择,但这取决于您的具体情况。

答案 1 :(得分:1)

我自己不喜欢这样的建议,但是......

如果您需要按顺序执行两个操作,请按顺序执行(您仍然可以在与main不同的线程上执行这些操作)。

如果您仍想在代码中分离任务,那么System.Parallel中的新构造将是合适的:

var task1 = Task.Factory.StartNew (() => FirstTask());
var task2 = task1.ContinueWith (frst => SecondTask ());

如果这是一种grok system.reactive的方法,请尝试Observable.GenerateInSequence - 但它肯定会有点过分。请记住,observable是可枚举的对应物,它最好以类似的方式使用(迭代数据)。它不是运行异步操作的工具。

编辑:我想承认我错了,理查德是对的 - 在我的回复时我对RX不太满意。现在我认为RX是启动异步操作的最自然方式。然而,理查德的答案有点吝啬,应该是:

var result =  
from x in XDownload.ToAsync()() 
from y in YDownload.ToAsync()() 
select y   

答案 2 :(得分:1)

可能还有以下几点:

    static IObservable<DownloadProgressChangedEventArgs> CreateDownloadFileObservable(string url, string fileName)
    {
       IObservable<DownloadProgressChangedEventArgs> observable =
           Observable.CreateWithDisposable<DownloadProgressChangedEventArgs>(o =>
        {
            var cancellationTokenSource = new CancellationTokenSource();
            Scheduler.TaskPool.Schedule
            (
                () =>
                {

                    Thread.Sleep(3000);
                    if (!cancellationTokenSource.Token.IsCancellationRequested)
                    {
                        WebClient client = new WebClient();
                        client.DownloadFileAsync(new Uri(url), fileName,fileName);


                        DownloadProgressChangedEventHandler prgChangedHandler = null;
                        prgChangedHandler = (s,e) =>
                            {                                                   
                                o.OnNext(e);
                            };


                        AsyncCompletedEventHandler handler = null;
                        handler = (s, e) =>
                        {
                            prgChangedHandler -= prgChangedHandler;                            
                            if (e.Error != null)
                            {
                                o.OnError(e.Error);
                            }
                            client.DownloadFileCompleted -= handler;
                            o.OnCompleted();
                        };
                        client.DownloadFileCompleted += handler;
                        client.DownloadProgressChanged += prgChangedHandler;
                    }
                    else
                    {
                        Console.WriteLine("Cancelling download of {0}",fileName);
                    }
                }
            );
            return cancellationTokenSource;
        }
        );
       return observable;
    }

    static void Main(string[] args)
    {

        var obs1 = CreateDownloadFileObservable("http://www.cnn.com", "cnn.htm");
        var obs2 = CreateDownloadFileObservable("http://www.bing.com", "bing.htm");

        var result = obs1.Concat(obs2);
        var subscription = result.Subscribe(a => Console.WriteLine("{0} -- {1}% complete ",a.UserState,a.ProgressPercentage), e=> Console.WriteLine(e.Message),()=> Console.WriteLine("Completed"));
        Console.ReadKey();
        subscription.Dispose();
        Console.WriteLine("Press a key to exit");
        Console.ReadKey();
}

您可以将CreateDownloadFileObservable转换为WebClient上的扩展方法,并删除方法定义中的WebClient client = new WebClient();,然后客户端woudl如下所示:

WebClient c = new WebClient();
c.CreateDownloadFileObservable ("www.bing.com","bing.htm");