Multithreading Silverlight Task.WaitAll使用Rx

Multithreading Silverlight Task.WaitAll使用Rx,multithreading,silverlight,system.reactive,Multithreading,Silverlight,System.reactive,我想同时调用两个Web服务,并在两者都完成后处理响应。我使用Rx的Observable.FromAsyncPattern方法调用Web服务。同时订阅多个IObservable的正确方法是什么 我尝试过使用Zip,但它似乎没有同时启动两个,只是在收到第一个结果后启动第二个结果。 编辑: 下面是Zip或其他一些解决方案的演示,这些解决方案并没有解决我的问题-- 预期结果: starting 1 starting 2 done sleeping 1 done sleeping 2 { a = 1, b

我想同时调用两个Web服务,并在两者都完成后处理响应。我使用Rx的Observable.FromAsyncPattern方法调用Web服务。同时订阅多个IObservable的正确方法是什么

我尝试过使用Zip,但它似乎没有同时启动两个,只是在收到第一个结果后启动第二个结果。
编辑: 下面是Zip或其他一些解决方案的演示,这些解决方案并没有解决我的问题--

预期结果:

starting 1
starting 2
done sleeping 1
done sleeping 2
{ a = 1, b = 1 }
finished

Rx连接提供了一个解决方案

可观察到。以及

当两个可观察序列都有可用值时匹配

演示:

var xsL = Observable.Return(1);
var xsR = Observable.Return(2);
Observable<int> both =  Observable.When(xsL.And(xsR).Then((a,b) => a + b));
var xsL=Observable.Return(1);
var xsR=可观察的回报率(2);
可观察两者=可观察。当(xsL.和(xsR).然后((a,b)=>a+b));

Zip是这里的正确答案:

Observable.Zip(someWebService(), otherWebService(), (some, other) => new { some, other })
    .Subscribe(someAndOther => {
        Console.WriteLine(Some is {0}, and Other is {1}", someAndOther.some, someAndOther.other);
    });
假设someWebService是一个签名如下的方法:

IObservable<SomeClass> someWebService()

然后,如果要阻止,可以在末尾抛出First()而不是Subscribe。

使用
Zip
扩展方法是这里的简单答案

如果有两个典型的异步调用(假设中只有一个参数):


Observable.Create不是Observable.FromAsyncPattern的正确模型;Zip、Merge和When建议的解决方案将适用于Observable.FromAsyncPattern

Observable.FromAsyncPattern在Observable.Create时添加并发性(从基础BeginXXX调用或使用AsyncSubject(Scheduler.ThreadPool)),默认情况下,将在当前线程上调度

Observable.FromAsyncPattern的更好模型是:

var observable1 = Observable.Create<int>(i =>
{
    return Scheduler.ThreadPool.Schedule(() =>
    {
        Console.WriteLine("starting 1");
        System.Threading.Thread.Sleep(4000);
        Console.WriteLine("done sleeping 1");
        i.OnNext(1);
        i.OnCompleted();
    });
});
var observable1=可观察。创建(i=>
{
返回调度程序.ThreadPool.Schedule(()=>
{
控制台写入线(“起始1”);
系统线程线程睡眠(4000);
Console.WriteLine(“完成睡眠1”);
i、 OnNext(1);
i、 未完成();
});
});

我在寻找其他东西时偶然发现了这个问题。对于为何不同时订阅Observer2,似乎存在一些困惑。答案很简单:默认情况下Rx不是多线程的。由您来管理线程/调度,这将有助于提高并发性@这件事难以捉摸,但我认为有必要作更深入的解释

具体而言;我们有以下(总结)代码

这里我们使用方便的可观察计时器工厂。它将创建一个序列,从订阅到完成,在给定的时间段发布值0。如果您对计时器的调度方式有偏好,那么您也可以提供一个可选的调度程序,例如

var observable1 = Observable.Timer(TimeSpan.FromSeconds(2), Scheduler.ThreadPool);
var observable2 = Observable.Timer(TimeSpan.FromSeconds(4), Scheduler.TaskPool);
默认调度程序(在为.NET 4.0库编写v.1.0.10621.0时)是scheduler.ThreadPool

您可以在我的Rx系列简介中了解更多有关日程安排的信息:

特别是调度和线程后处理


我希望这能澄清原帖中的问题。

7小时后第一次回答,你比我快了3分钟。干得好,保罗。谢谢,但是合并/聚合技巧似乎也没有同时订阅所有的可观察对象,这就是我正在尝试做的。我以前也这么做过,但我认为只有当第一个结果从callX返回时,Caly才会订阅。请参阅我的编辑。@foson-这取决于可观察对象使用的默认计划程序。如果您将
.SubscribeOn(Scheduler.ThreadPool)
添加到
observable1
中,代码将按需要工作。哇,这很有趣。因此,默认情况下,我们订阅当前线程并观察线程池?@foson-No,每个扩展方法都有自己的默认调度程序。当前构建(1.0.10621.0)具有以下默认值-CurrentThread:Create、Generate(不含时间跨度)、Range、Repeat、TooObservable;立即:空、合并、返回、开始、抛出;线程池:延迟、生成(带时间跨度)、间隔、采样、启动、节流、时间间隔、超时、计时器、时间戳、ToAsync、窗口。我知道调用方在默认计划程序上订阅和观察,除非显式调用
SubscribeOn
/
ObserveOn
。@Sergey-语义上
Zip
&
CombineTest
在这种情况下是相同的,但是,如果每个可观察对象可以产生多个值,那么
combinelateest
可能会遗漏值或产生可能没有意义的“中间”配对。例如,如果我有一个产生a1和a2的A,B产生b1和b2,那么A.Zip(B)只产生(a1,b1)和(a2,b2),但是A.CombineTest(B)可以产生许多结果(a1,b1),(a2,b1)和(a2,b2)或者(a1,b1),(a1,b2)和(a2,b2)或者(a2,b1)和(a2,b2)或者(a1,b2)和(a2,b2)
Zip
通常是正确的选择。我的产品是否可观察。Create甚至是可观察的正确模型。FromAsyncPattern?
Observable.Merge(
    observable1.Select(_ => Unit.Default),
    observable2.Select(_ => Unit.Default),
    observable3.Select(_ => Unit.Default),
    observable4.Select(_ => Unit.Default))
.Aggregate(Unit.Default, (acc, _) => acc)
.Subscribe(_ => Console.WriteLine("They all finished!");
Func<X1, IObservable<X2>> callX = Observable.FromAsyncPattern<X1, X2>(...);
Func<Y1, IObservable<Y2>> callY = Observable.FromAsyncPattern<Y1, Y2>(...);
callX(x1).Zip(callY(y1), (x2, y2) =>
{
    ...
});
var observable1 = Observable.Create<int>(i =>
{
    return Scheduler.ThreadPool.Schedule(() =>
    {
        Console.WriteLine("starting 1");
        System.Threading.Thread.Sleep(4000);
        Console.WriteLine("done sleeping 1");
        i.OnNext(1);
        i.OnCompleted();
    });
});
var observable1 = Observable.Create<int>(i =>
    {
        System.Threading.Thread.Sleep(2000);
        i.OnNext(1);
        i.OnCompleted();
        return () => { };
    });
var observable2 = Observable.Create<int>(i =>
{
    System.Threading.Thread.Sleep(4000);
    i.OnNext(1);
    i.OnCompleted();
    return () => { };
});

var m = observable1.Zip(observable2, (a, b) => new { a, b });
m.Subscribe(Console.WriteLine);
var observable1 = Observable.Timer(TimeSpan.FromSeconds(2));
var observable2 = Observable.Timer(TimeSpan.FromSeconds(4));

var zipped = observable1.Zip(observable2, (a, b) => new { a, b });
zipped.Subscribe(Console.WriteLine);
var observable1 = Observable.Timer(TimeSpan.FromSeconds(2), Scheduler.ThreadPool);
var observable2 = Observable.Timer(TimeSpan.FromSeconds(4), Scheduler.TaskPool);