Tôi cố gắng để liệt kê một lớn IEnumerable
một lần, và quan sát sự liệt kê với những hoạt động khác nhau kèm theo ( Count
, Sum
, Average
vv). Cách rõ ràng là chuyển đổi nó thành một IObservable
phương thức ToObservable
, và sau đó đăng ký một người quan sát vào nó. Tôi nhận thấy rằng điều này chậm hơn nhiều so với các phương thức khác, như thực hiện một vòng lặp đơn giản và thông báo cho người quan sát trên mỗi lần lặp hoặc sử dụng Observable.Create
phương thức thay vì ToObservable
. Sự khác biệt là đáng kể: nó chậm hơn 20-30 lần. Đó là những gì nó là, hoặc tôi đang làm gì đó sai?
using System;
using System.Diagnostics;
using System.Linq;
using System.Reactive.Disposables;
using System.Reactive.Linq;
using System.Reactive.Subjects;
using System.Reactive.Threading.Tasks;
public static class Program
{
static void Main(string[] args)
{
const int COUNT = 10_000_000;
Method1(COUNT);
Method2(COUNT);
Method3(COUNT);
}
static void Method1(int count)
{
var source = Enumerable.Range(0, count);
var subject = new Subject<int>();
var stopwatch = Stopwatch.StartNew();
source.ToObservable().Subscribe(subject);
Console.WriteLine($"ToObservable: {stopwatch.ElapsedMilliseconds:#,0} msec");
}
static void Method2(int count)
{
var source = Enumerable.Range(0, count);
var subject = new Subject<int>();
var stopwatch = Stopwatch.StartNew();
foreach (var item in source) subject.OnNext(item);
subject.OnCompleted();
Console.WriteLine($"Loop & Notify: {stopwatch.ElapsedMilliseconds:#,0} msec");
}
static void Method3(int count)
{
var source = Enumerable.Range(0, count);
var subject = new Subject<int>();
var stopwatch = Stopwatch.StartNew();
Observable.Create<int>(o =>
{
foreach (var item in source) o.OnNext(item);
o.OnCompleted();
return Disposable.Empty;
}).Subscribe(subject);
Console.WriteLine($"Observable.Create: {stopwatch.ElapsedMilliseconds:#,0} msec");
}
}
Đầu ra:
ToObservable: 7,576 msec
Loop & Notify: 273 msec
Observable.Create: 511 msec
.NET Core 3.0, C # 8, System.Reactive 4.3.2, Windows 10, Ứng dụng bảng điều khiển, Bản phát hành được xây dựng
Cập nhật: Đây là một ví dụ về chức năng thực tế tôi muốn đạt được:
var source = Enumerable.Range(0, 10_000_000).Select(i => (long)i);
var subject = new Subject<long>();
var cntTask = subject.Count().ToTask();
var sumTask = subject.Sum().ToTask();
var avgTask = subject.Average().ToTask();
source.ToObservable().Subscribe(subject);
Console.WriteLine($"Count: {cntTask.Result:#,0}, Sum: {sumTask.Result:#,0}, Average: {avgTask.Result:#,0.0}");
Đầu ra:
Đếm: 10.000.000, Tổng: 49.999.995.000.000, Trung bình: 4.999.999,5
Sự khác biệt quan trọng của phương pháp này so với việc sử dụng các toán tử LINQ tiêu chuẩn , là liệt kê nguồn chỉ được liệt kê một lần.
Thêm một quan sát: sử dụng ToObservable(Scheduler.Immediate)
nhanh hơn một chút (khoảng 20%) so với ToObservable()
.