您好'我已经尝试过101个Rx示例中的一个:
static IEnumerable<int> GenerateAlternatingFastAndSlowEvents()
{
int i = 0;
while (true)
{
if (i > 1000)
{
yield break;
}
yield return i;
Thread.Sleep(i++ % 10 < 5 ? 500 : 1000);
}
}
private static void Main()
{
var observable = GenerateAlternatingFastAndSlowEvents().ToObservable().Timestamp();
var throttled = observable.Throttle(TimeSpan.FromMilliseconds(750));
using (throttled.Subscribe(x => Console.WriteLine("{0}: {1}", x.Value, x.Timestamp)))
{
Console.WriteLine("Press any key to unsubscribe");
Console.ReadKey();
}
Console.WriteLine("Press any key to exit");
Console.ReadKey();
}
我不明白为什么“按任意键取消订阅”这一行从未显示过。我的理解是订阅是异步的,您订阅并且它立即返回。我错过了什么导致我的主线程阻塞?
答案 0 :(得分:7)
阻止是由于while (true)
和IEnumerable<T>.ToObservable()
扩展方法上的可枚举循环组合,默认为CurrentThreadScheduler
。
如果您将Scheduler.TaskPool
(或者在.NET 4之前的Scheduler.ThreadPool
)提供给ToObservable
的重载,您应该会看到您期望的行为(尽管它不会在主线程上呼叫您的订户,仅供参考。
话虽如此,我认为您会发现Thread.Sleep
和Throttle
的组合会按预期运作。您可能最好创建一个使用调度程序来安排延迟的自定义observable。
答案 1 :(得分:2)
我同意理查德的观点。
.ToObservable()
的实现如下:
public static IObservable<TSource> ToObservable<TSource>(
this IEnumerable<TSource> source)
{
if (source == null)
{
throw new ArgumentNullException("source");
}
return source.ToObservable<TSource>(Scheduler.CurrentThread);
}
它使用.ToObservable(IScheduler)
调用Scheduler.CurrentThread
重载,因为您使用.Sleep(...)
导致延迟,所以在代码超出.Subscribe(...)
之前必须完成observable方法。试想一下,如果这个代码都在一个线程上运行,那么这个代码的行为是什么(就是这样。)
为了解决这个问题,您可以使用Richard建议的任务池或线程池调度程序,但我认为您的代码存在更基本的问题。那就是你正在使用“老派”线程睡觉,而不是依赖于Rx方法。
尝试此操作以生成您的observable:
var observable =
Observable
.GenerateWithTime(0, i => i <= 1000, i => i + 1,
i => i, i => TimeSpan.FromMilliseconds(i % 10 < 5 ? 500 : 1000))
.Timestamp();
GenerateWithTime(...)
会执行您的GenerateAlternatingFastAndSlowEvents
方法所做的所有操作,但它会直接创建observable并使用引擎盖下的Scheduler.ThreadPool
进行操作,因此您无需指定任何调度程序。