LINQ是一种拉取模式,在查询过程中数据项是被逐个拉取出来的。例如有IEnumerable<string>提供给我们字符串值。当迭代它时,并不知道每个迭代会花费多长时间。如果使用常规的foreach或其他的同步迭代构造方式,我们将阻塞线程直到得到下一个值,这可能导致整个处理非常慢。这种场景被称为“基于拉取”的方式。基于推送的方式即生产者通知客户端有新值要处理。这将把工作推给生产者,而客户端在等待另一个值的时候可以做其他事情。因此目标是实现类似于IEnumerable的异步版本的一个机制,可以生产一组序列值并按顺序通知消费者处理这些值,直到序列处理完成或抛出异常。
Reactive Extensions(Rx)把事件看作是依次到达的数据序列。因此,将Rx认作是LINQ to events(基于IObservable<T>)也是可以的,它与其他LINQ提供者的主要区别在于,Rx采用“推送”模式,就是说,Rx的查询规定了在事件到达时程序该如何响应。Rx在LINQ的基础上构建,增加了一些功能强大的操作符作为扩展方法。
IObservable
(一)将普通集合转换为异步可观察的集合
static void Main(string[] args) { foreach (int i in EnumerableEventSequence()) { Console.WriteLine($"IEnumerable【{i}】:{DateTime.Now.ToString("HH:mm:ss.fff")}"); } Console.WriteLine($"=====【{DateTime.Now.ToString("HH: mm:ss.fff")}】IEnumerable 方式迭代完成"); IObservable<int> o = EnumerableEventSequence().ToObservable(); using (IDisposable subscription = o.Subscribe((i) => { Console.WriteLine($"IObservable【{i}】:{DateTime.Now.ToString("HH:mm:ss.fff")}"); })) { Console.WriteLine($"=====【{DateTime.Now.ToString("HH: mm:ss.fff")}】IObservable 方式迭代完成"); } o = EnumerableEventSequence().ToObservable().SubscribeOn(TaskPoolScheduler.Default); using (IDisposable subscription = o.Subscribe((i) => { Console.WriteLine($"IObservable async【{i}】:{DateTime.Now.ToString("HH:mm:ss.fff")}"); })) { Console.WriteLine($"=====【{DateTime.Now.ToString("HH: mm:ss.fff")}】IObservable async 方式迭代完成"); //此处与迭代并行执行 Console.ReadLine(); } Console.WriteLine("Hello World!"); Console.ReadLine(); } static IEnumerable<int> EnumerableEventSequence() { for (int i = 0; i < 10; i++) { Thread.Sleep(TimeSpan.FromSeconds(1)); yield return i; } }
(二).NET 事件转换
var timer = new System.Timers.Timer(interval: 1000) { Enabled = true }; var ticks = Observable.FromEventPattern(timer, "Elapsed"); ticks.Subscribe(data => Trace.WriteLine($"OnNext:{((ElapsedEventArgs)data.EventArgs).SignalTime}"));