ReactiveX 学习笔记(12)调度器
Schedulers, threading and testing
本文的主题为调度器,多线程以及测试。
SubscribeOn / ObserveOn
- SubscribeOn / ObserveOn 用来指定数据流和观察者所运行的线程。
这里数据流的运行是指数据流创建,转化,发送数据以及最后销毁的全过程。
这里观察者的运行是指数据流发送数据和观察者观察数据的过程。
SubscribeOn / ObserveOn 指定线程是通过指定调度器来完成的。 - SubscribeOn 同时指定数据流和观察者所运行的线程。
SubscribeOn 截获对 Subscribe 及其之后的 Dispose 方法的调用,将其转化为异步操作。 - ObserveOn 仅限于指定观察者运行的线程。
ObserveOn 截获对 OnNext OnCompleted OnError 方法的调用,将其转化为异步操作。
也就是说 ObserveOn 指定 Subscribe 方法内 3 个回调函数在哪个线程上运行。 - SubscribeOn 指定的范围大,同时使用的情况下 ObserveOn 指定的优先度高。
ReactiveX - SubscribeOn operator
ReactiveX - ObserveOn operator
ObserveOn and SubscribeOn - where the work is being done
- RxNET
- 缺省情况下,数据流以及观察者运行的线程均与 Subscribe 的调用者线程相同。
Console.WriteLine(MethodBase.GetCurrentMethod().Name);
Console.WriteLine("Starting on threadId:{0}", Thread.CurrentThread.ManagedThreadId);
var source = Observable.Create<int>(
o =>
{
Console.WriteLine("Invoked on threadId:{0}", Thread.CurrentThread.ManagedThreadId);
o.OnNext(1);
o.OnNext(2);
o.OnNext(3);
o.OnCompleted();
Console.WriteLine("Finished on threadId:{0}", Thread.CurrentThread.ManagedThreadId);
return Disposable.Empty;
});
source
.Subscribe(
o => Console.WriteLine("Received {1} on threadId:{0}", Thread.CurrentThread.ManagedThreadId,
o),
() => Console.WriteLine("OnCompleted on threadId:{0}", Thread.CurrentThread.ManagedThreadId));
Console.WriteLine("Subscribed on threadId:{0}", Thread.CurrentThread.ManagedThreadId);
/*
Starting on threadId:1
Invoked on threadId:1
Received 1 on threadId:1
Received 2 on threadId:1
Received 3 on threadId:1
OnCompleted on threadId:1
Finished on threadId:1
Subscribed on threadId:1
*/
- SubscribeOn
Console.WriteLine(MethodBase.GetCurrentMethod().Name);
Console.WriteLine("Starting on threadId:{0}", Thread.CurrentThread.ManagedThreadId);
var source = Observable.Create<int>(
o =>
{
Console.WriteLine("Invoked on threadId:{0}", Thread.CurrentThread.ManagedThreadId);
o.OnNext(1);
o.OnNext(2);
o.OnNext(3);
o.OnCompleted();
Console.WriteLine("Finished on threadId:{0}", Thread.CurrentThread.ManagedThreadId);
return Disposable.Empty;
});
source
.SubscribeOn(Scheduler.Default)
.Subscribe(
o => Console.WriteLine("Received {1} on threadId:{0}", Thread.CurrentThread.ManagedThreadId,
o),
() => Console.WriteLine("OnCompleted on threadId:{0}", Thread.CurrentThread.ManagedThreadId));
Console.WriteLine("Subscribed on threadId:{0}", Thread.CurrentThread.ManagedThreadId);
/*
Starting on threadId:1
Subscribed on threadId:1
Invoked on threadId:4
Received 1 on threadId:4
Received 2 on threadId:4
Received 3 on threadId:4
OnCompleted on threadId:4
Finished on threadId:4
*/
- ObserveOn
Console.WriteLine("Starting on threadId:{0}", Thread.CurrentThread.ManagedThreadId);
var source = Observable.Create<int>(
o =>
{
Console.WriteLine("Invoked on threadId:{0}", Thread.CurrentThread.ManagedThreadId);
o.OnNext(1);
o.OnNext(2);
o.OnNext(3);
o.OnCompleted();
Console.WriteLine("Finished on threadId:{0}", Thread.CurrentThread.ManagedThreadId);
return Disposable.Empty;
});
source
.ObserveOn(Scheduler.Default)
.Subscribe(
o => Console.WriteLine("Received {1} on threadId:{0}", Thread.CurrentThread.ManagedThreadId,
o),
() => Console.WriteLine("OnCompleted on threadId:{0}", Thread.CurrentThread.ManagedThreadId));
Console.WriteLine("Subscribed on threadId:{0}", Thread.CurrentThread.ManagedThreadId);
/*
Starting on threadId:1
Invoked on threadId:1
Finished on threadId:1
Subscribed on threadId:1
Received 1 on threadId:6
Received 2 on threadId:6
Received 3 on threadId:6
OnCompleted on threadId:6
*/
- SubscribeOn + ObserveOn
Console.WriteLine(MethodBase.GetCurrentMethod().Name);
Console.WriteLine("Starting on threadId:{0}", Thread.CurrentThread.ManagedThreadId);
var source = Observable.Create<int>(
o =>
{
Console.WriteLine("Invoked on threadId:{0}", Thread.CurrentThread.ManagedThreadId);
o.OnNext(1);
o.OnNext(2);
o.OnNext(3);
o.OnCompleted();
Console.WriteLine("Finished on threadId:{0}", Thread.CurrentThread.ManagedThreadId);
return Disposable.Empty;
});
source
.SubscribeOn(Scheduler.Default)
.ObserveOn(Scheduler.Default)
.Subscribe(
o => Console.WriteLine("Received {1} on threadId:{0}", Thread.CurrentThread.ManagedThreadId,
o),
() => Console.WriteLine("OnCompleted on threadId:{0}", Thread.CurrentThread.ManagedThreadId));
Console.WriteLine("Subscribed on threadId:{0}", Thread.CurrentThread.ManagedThreadId);
/*
Starting on threadId:1
Subscribed on threadId:1
Invoked on threadId:4
Finished on threadId:4
Received 1 on threadId:7
Received 2 on threadId:7
Received 3 on threadId:7
OnCompleted on threadId:7
*/
- RxJava
val subject = BehaviorSubject.create<Int>()
subject.subscribe { i -> println("Received $i on ${Thread.currentThread().id}") }
val i = intArrayOf(1) // naughty side-effects for examples only ;)
val r = Runnable {
synchronized(i) {
println("onNext(${i[0]}) on ${Thread.currentThread().id}")
subject.onNext(i[0]++)
}
}
r.run() // Execute on main thread
Thread(r).start()
Thread(r).start()
/*
onNext(1) on 1
Received 1 on 1
onNext(2) on 11
Received 2 on 11
onNext(3) on 12
Received 3 on 12
*/
println("Main: ${Thread.currentThread().id}")
Observable.create<Int> { o ->
println("Created on ${Thread.currentThread().id}")
o.onNext(1)
o.onNext(2)
o.onComplete()
}
.subscribe { i -> println("Received $i on ${Thread.currentThread().id}") }
println("Finished main: ${Thread.currentThread().id}")
/*
Main: 1
Created on 1
Received 1 on 1
Received 2 on 1
Finished main: 1
*/
println("Main: ${Thread.currentThread().id}")
Observable.create<Int> { o ->
println("Created on ${Thread.currentThread().id}")
o.onNext(1)
o.onNext(2)
o.onComplete()
}
.subscribeOn(Schedulers.newThread())
.subscribe { i -> println("Received $i on ${Thread.currentThread().id}") }
println("Finished main: ${Thread.currentThread().id}")
/*
Main: 1
Finished main: 1
Created on 15
Received 1 on 15
Received 2 on 15
*/
println("Main: ${Thread.currentThread().id}")
val s = Observable.interval(100, TimeUnit.MILLISECONDS)
.subscribe { i -> println("Received $i on ${Thread.currentThread().id}") }
println("Finished main: ${Thread.currentThread().id}")
readLine()
s.dispose()
/*
Main: 1
Finished main: 1
Received 0 on 16
Received 1 on 16
Received 2 on 16
Received 3 on 16
...
*/
Observable.create<Int> { o ->
println("Created on ${Thread.currentThread().id}")
o.onNext(1)
o.onNext(2)
o.onComplete()
}
.observeOn(Schedulers.newThread())
.subscribe { i -> println("Received $i on ${Thread.currentThread().id}") }
/*
Created on 1
Received 1 on 17
Received 2 on 17
*/
Observable.create<Int> { o ->
println("Created on " + Thread.currentThread().id)
o.onNext(1)
o.onNext(2)
o.onComplete()
}
.doOnNext { i -> println("Before $i on ${Thread.currentThread().id}") }
.observeOn(Schedulers.newThread())
.doOnNext { i -> println("After $i on ${Thread.currentThread().id}") }
.subscribe()
/*
Created on 1
Before 1 on 1
Before 2 on 1
After 1 on 18
After 2 on 18
*/
调度器的使用
- RxNET
状态
var scheduler = NewThreadScheduler.Default;
var myName = "Lee";
scheduler.Schedule(
() => Console.WriteLine("myName = {0}", myName));
myName = "John";
/*
myName = John
*/
var scheduler = ImmediateScheduler.Instance;
var myName = "Lee";
scheduler.Schedule(
() => Console.WriteLine("myName = {0}", myName));
myName = "John";
/*
myName = Lee
*/
var scheduler = NewThreadScheduler.Default;
var myName = "Lee";
scheduler.Schedule(myName,
(_, state) =>
{
Console.WriteLine("myName = {0}", state);
return Disposable.Empty;
});
myName = "John";
/*
myName = Lee
*/
var scheduler = ImmediateScheduler.Instance;
var myName = "Lee";
scheduler.Schedule(myName,
(_, state) =>
{
Console.WriteLine("myName = {0}", state);
return Disposable.Empty;
});
myName = "John";
/*
myName = Lee
*/
var scheduler = NewThreadScheduler.Default;
var list = new List<int>();
scheduler.Schedule(list,
(innerScheduler, state) =>
{
Console.WriteLine(state.Count);
return Disposable.Empty;
});
list.Add(1);
/*
1
*/
var scheduler = ImmediateScheduler.Instance;
var list = new List<int>();
scheduler.Schedule(list,
(innerScheduler, state) =>
{
Console.WriteLine(state.Count);
return Disposable.Empty;
});
list.Add(1);
/*
0
*/
时间
var scheduler = ImmediateScheduler.Instance;
var delay = TimeSpan.FromSeconds(1);
Console.WriteLine("Before schedule at {0:o}", DateTime.Now);
scheduler.Schedule(delay,
() => Console.WriteLine("Inside schedule at {0:o}", DateTime.Now));
Console.WriteLine("After schedule at {0:o}", DateTime.Now);
Console.ReadKey();
/*
Before schedule at 2018-08-01T11:20:26.0042252+09:00
Inside schedule at 2018-08-01T11:20:27.0232835+09:00
After schedule at 2018-08-01T11:20:27.0232835+09:00
*/
取消任务
var scheduler = NewThreadScheduler.Default;
var delay = TimeSpan.FromSeconds(1);
Console.WriteLine("Before schedule at {0:o}", DateTime.Now);
var token = scheduler.Schedule(delay,
() => Console.WriteLine("Inside schedule at {0:o}", DateTime.Now));
Console.WriteLine("After schedule at {0:o}", DateTime.Now);
token.Dispose();
Console.ReadKey();
/*
Before schedule at 2018-08-01T11:20:27.9713377+09:00
After schedule at 2018-08-01T11:20:27.9743379+09:00
*/
public static IDisposable Work(IScheduler scheduler, List<int> list)
{
var tokenSource = new CancellationTokenSource();
var cancelToken = tokenSource.Token;
var task = new Task(() =>
{
Console.WriteLine();
for (int i = 0; i < 1000; i++)
{
var sw = new SpinWait();
for (int j = 0; j < 3000; j++) sw.SpinOnce();
Console.Write(".");
list.Add(i);
if (cancelToken.IsCancellationRequested)
{
Console.WriteLine("Cancelation requested");
//cancelToken.ThrowIfCancellationRequested();
return;
}
}
}, cancelToken);
task.Start();
return Disposable.Create(tokenSource.Cancel);
}
var scheduler = NewThreadScheduler.Default;
var list = new List<int>();
Console.WriteLine("Enter to quit:");
var token = scheduler.Schedule(list, Work);
Console.ReadLine();
Console.WriteLine("Cancelling...");
token.Dispose();
Console.WriteLine("Cancelled");
/*
Enter to quit:
...........
Cancelling...
Cancelled
.Cancelation requested
*/
递归
var scheduler = NewThreadScheduler.Default;
Action<Action> work = (Action self)
=>
{
Console.WriteLine("Running");
self();
};
Console.WriteLine("Enter to quit:");
var token = scheduler.Schedule(work);
Console.ReadLine();
Console.WriteLine("Cancelling");
token.Dispose();
Console.WriteLine("Cancelled");
/*
Enter to quit:
Running
Running
Running
Running
Cancelling
Running
Running
Cancelled
*/
- RxJava
val scheduler = Schedulers.trampoline()
val worker = scheduler.createWorker()
worker.schedule(
{ println("Action") })
/*
Action
*/
val scheduler = Schedulers.newThread()
val start = System.currentTimeMillis()
val worker = scheduler.createWorker()
worker.schedule(
{ println(System.currentTimeMillis() - start) },
5, TimeUnit.SECONDS)
worker.schedule(
{ println(System.currentTimeMillis() - start) },
5, TimeUnit.SECONDS)
/*
5005
5005
*/
val scheduler = Schedulers.newThread()
val start = System.currentTimeMillis()
val worker = scheduler.createWorker()
worker.schedule(
{
println(System.currentTimeMillis() - start)
worker.dispose()
},
5, TimeUnit.SECONDS)
worker.schedule(
{ println(System.currentTimeMillis() - start) },
5, TimeUnit.SECONDS)
/*
5001
*/
val scheduler = Schedulers.newThread()
val worker = scheduler.createWorker()
worker.schedule {
try {
Thread.sleep(2000)
println("Action completed")
} catch (e: InterruptedException) {
println("Action interrupted")
}
}
Thread.sleep(500)
worker.dispose()
/*
Action interrupted
*/
调度器的种类
- ImmediateScheduler
- CurrentThreadScheduler
- RxNET
private static void ScheduleTasks(IScheduler scheduler)
{
Action leafAction = () => Console.WriteLine("----leafAction.");
Action innerAction = () =>
{
Console.WriteLine("--innerAction start.");
scheduler.Schedule(leafAction);
Console.WriteLine("--innerAction end.");
};
Action outerAction = () =>
{
Console.WriteLine("outer start.");
scheduler.Schedule(innerAction);
Console.WriteLine("outer end.");
};
scheduler.Schedule(outerAction);
}
ScheduleTasks(Scheduler.CurrentThread);
/*
outer start.
outer end.
--innerAction start.
--innerAction end.
----leafAction.
*/
ScheduleTasks(Scheduler.Immediate);
/*
outer start.
--innerAction start.
----leafAction.
--innerAction end.
outer end.
*/
- RxJava
Schedulers.immediate() 被废除了。
val scheduler = Schedulers.trampoline()
val worker = scheduler.createWorker()
worker.schedule {
println("Start")
worker.schedule { println("Inner") }
println("End")
}
/*
Start
End
Inner
*/
- DispatcherScheduler
- EventLoopScheduler
- NewThreadScheduler
- ThreadPoolScheduler
- TaskPoolScheduler
- RxNET
private static IDisposable OuterAction(IScheduler scheduler, string state)
{
Console.WriteLine("{0} start. ThreadId:{1}",
state,
Thread.CurrentThread.ManagedThreadId);
scheduler.Schedule(state + ".inner", InnerAction);
Console.WriteLine("{0} end. ThreadId:{1}",
state,
Thread.CurrentThread.ManagedThreadId);
return Disposable.Empty;
}
private static IDisposable InnerAction(IScheduler scheduler, string state)
{
Console.WriteLine("{0} start. ThreadId:{1}",
state,
Thread.CurrentThread.ManagedThreadId);
scheduler.Schedule(state + ".Leaf", LeafAction);
Console.WriteLine("{0} end. ThreadId:{1}",
state,
Thread.CurrentThread.ManagedThreadId);
return Disposable.Empty;
}
private static IDisposable LeafAction(IScheduler scheduler, string state)
{
Console.WriteLine("{0}. ThreadId:{1}",
state,
Thread.CurrentThread.ManagedThreadId);
return Disposable.Empty;
}
Console.WriteLine("Starting on thread :{0}", Thread.CurrentThread.ManagedThreadId);
NewThreadScheduler.Default.Schedule("A", OuterAction);
NewThreadScheduler.Default.Schedule("B", OuterAction);
/*
Starting on thread :1
A start. ThreadId:13
A end. ThreadId:13
A.inner start. ThreadId:13
A.inner end. ThreadId:13
B start. ThreadId:14
B end. ThreadId:14
B.inner start. ThreadId:14
B.inner end. ThreadId:14
B.inner.Leaf. ThreadId:14
A.inner.Leaf. ThreadId:13
*/
Console.WriteLine("Starting on thread :{0}", Thread.CurrentThread.ManagedThreadId);
ThreadPoolScheduler.Instance.Schedule("A", OuterAction);
ThreadPoolScheduler.Instance.Schedule("B", OuterAction);
/*
Starting on thread :1
A start. ThreadId:5
A end. ThreadId:5
A.inner start. ThreadId:5
A.inner end. ThreadId:5
A.inner.Leaf. ThreadId:5
B start. ThreadId:4
B end. ThreadId:4
B.inner start. ThreadId:5
B.inner end. ThreadId:5
B.inner.Leaf. ThreadId:4
*/
Console.WriteLine("Starting on thread :{0}", Thread.CurrentThread.ManagedThreadId);
TaskPoolScheduler.Default.Schedule("A", OuterAction);
TaskPoolScheduler.Default.Schedule("B", OuterAction);
/*
Starting on thread :1
A start. ThreadId:4
A end. ThreadId:4
A.inner start. ThreadId:15
A.inner end. ThreadId:15
A.inner.Leaf. ThreadId:4
B start. ThreadId:5
B end. ThreadId:5
B.inner start. ThreadId:15
B.inner end. ThreadId:15
B.inner.Leaf. ThreadId:4
*/
- RxJava
private fun printThread(message: String) {
println("$message on ${Thread.currentThread().id}")
}
printThread("Main")
val scheduler = Schedulers.newThread()
val worker = scheduler.createWorker()
worker.schedule {
printThread("Start")
worker.schedule { printThread("Inner") }
printThread("End")
}
Thread.sleep(500)
worker.schedule { printThread("Again") }
/*
Main on 1
Start on 13
End on 13
Inner on 13
Again on 13
*/
- TestScheduler
测试调度器
- RxNET
var scheduler = new TestScheduler();
var wasExecuted = false;
scheduler.Schedule(() => wasExecuted = true);
Console.WriteLine(wasExecuted); // False
scheduler.AdvanceBy(1); //execute 1 tick of queued actions
Console.WriteLine(wasExecuted); // True
/*
False
True
*/
var scheduler = new TestScheduler();
scheduler.Schedule(() => Console.WriteLine("A")); //Schedule immediately
scheduler.Schedule(TimeSpan.FromTicks(10), () => Console.WriteLine("B"));
scheduler.Schedule(TimeSpan.FromTicks(20), () => Console.WriteLine("C"));
Console.WriteLine("scheduler.AdvanceTo(1);");
scheduler.AdvanceTo(1);
Console.WriteLine("scheduler.AdvanceTo(10);");
scheduler.AdvanceTo(10);
Console.WriteLine("scheduler.AdvanceTo(15);");
scheduler.AdvanceTo(15);
Console.WriteLine("scheduler.AdvanceTo(20);");
scheduler.AdvanceTo(20);
/*
scheduler.AdvanceTo(1);
A
scheduler.AdvanceTo(10);
B
scheduler.AdvanceTo(15);
scheduler.AdvanceTo(20);
C
*/
var scheduler = new TestScheduler();
scheduler.Schedule(() => Console.WriteLine("A")); //Schedule immediately
scheduler.Schedule(TimeSpan.FromTicks(10), () => Console.WriteLine("B"));
scheduler.Schedule(TimeSpan.FromTicks(20), () => Console.WriteLine("C"));
Console.WriteLine("scheduler.AdvanceBy(1);");
scheduler.AdvanceBy(1);
Console.WriteLine("scheduler.AdvanceBy(9);");
scheduler.AdvanceBy(9);
Console.WriteLine("scheduler.AdvanceBy(5);");
scheduler.AdvanceBy(5);
Console.WriteLine("scheduler.AdvanceBy(5);");
scheduler.AdvanceBy(5);
/*
scheduler.AdvanceBy(1);
A
scheduler.AdvanceBy(9);
B
scheduler.AdvanceBy(5);
scheduler.AdvanceBy(5);
C
*/
var scheduler = new TestScheduler();
scheduler.Schedule(() => Console.WriteLine("A")); //Schedule immediately
scheduler.Schedule(TimeSpan.FromTicks(10), () => Console.WriteLine("B"));
scheduler.Schedule(TimeSpan.FromTicks(20), () => Console.WriteLine("C"));
Console.WriteLine("scheduler.Start();");
scheduler.Start();
Console.WriteLine("scheduler.Clock:{0}", scheduler.Clock);
/*
scheduler.Start();
A
B
C
scheduler.Clock:20
*/
Console.WriteLine(MethodBase.GetCurrentMethod().Name);
var scheduler = new TestScheduler();
scheduler.Schedule(() => Console.WriteLine("A"));
scheduler.Schedule(TimeSpan.FromTicks(10), () => Console.WriteLine("B"));
scheduler.Schedule(TimeSpan.FromTicks(20), () => Console.WriteLine("C"));
Console.WriteLine("scheduler.Start();");
scheduler.Start();
Console.WriteLine("scheduler.Clock:{0}", scheduler.Clock);
scheduler.Schedule(() => Console.WriteLine("D"));
scheduler.Start();
Console.WriteLine("scheduler.Clock:{0}", scheduler.Clock);
/*
scheduler.Start();
A
B
C
scheduler.Clock:20
D
scheduler.Clock:21
*/
var scheduler = new TestScheduler();
scheduler.Schedule(() => Console.WriteLine("A"));
scheduler.Schedule(TimeSpan.FromTicks(10), () => Console.WriteLine("B"));
scheduler.Schedule(TimeSpan.FromTicks(15), scheduler.Stop);
scheduler.Schedule(TimeSpan.FromTicks(20), () => Console.WriteLine("C"));
Console.WriteLine("scheduler.Start();");
scheduler.Start();
Console.WriteLine("scheduler.Clock:{0}", scheduler.Clock);
/*
scheduler.Start();
A
B
scheduler.Clock:15
*/
var scheduler = new TestScheduler();
scheduler.Schedule(TimeSpan.FromTicks(10), () => Console.WriteLine("A"));
scheduler.Schedule(TimeSpan.FromTicks(10), () => Console.WriteLine("B"));
scheduler.Schedule(TimeSpan.FromTicks(10), () => Console.WriteLine("C"));
Console.WriteLine("scheduler.Start();");
scheduler.Start();
Console.WriteLine("scheduler.Clock:{0}", scheduler.Clock);
/*
scheduler.Start();
A
B
C
scheduler.Clock:10
*/
var expectedValues = new long[] { 0, 1, 2, 3, 4 };
var actualValues = new List<long>();
var scheduler = new TestScheduler();
var interval = Observable
.Interval(TimeSpan.FromSeconds(1), scheduler)
.Take(5);
interval.Subscribe(actualValues.Add);
scheduler.Start();
Console.WriteLine(Enumerable.SequenceEqual(expectedValues, actualValues));
/*
True
*/
var scheduler = new TestScheduler();
var never = Observable.Never<int>();
var exceptionThrown = false;
never.Timeout(TimeSpan.FromMinutes(1), scheduler)
.Subscribe(
i => Console.WriteLine("This will never run."),
ex => exceptionThrown = true);
scheduler.Start();
Console.WriteLine(exceptionThrown);
/*
True
*/
var scheduler = new TestScheduler();
var source = Observable.Interval(TimeSpan.FromSeconds(1), scheduler)
.Take(4);
var testObserver = scheduler.Start(
() => source,
0,
0,
TimeSpan.FromSeconds(5).Ticks);
Console.WriteLine("Time is {0} ticks", scheduler.Clock);
Console.WriteLine("Received {0} notifications", testObserver.Messages.Count);
foreach (Recorded<Notification<long>> message in testObserver.Messages)
{
Console.WriteLine("{0} @ {1}", message.Value, message.Time);
}
/*
Time is 50000000 ticks
Received 5 notifications
OnNext(0) @ 10000001
OnNext(1) @ 20000001
OnNext(2) @ 30000001
OnNext(3) @ 40000001
OnCompleted() @ 40000001
*/
var scheduler = new TestScheduler();
var source = Observable.Interval(TimeSpan.FromSeconds(1), scheduler)
.Take(4);
var testObserver = scheduler.Start(
() => Observable.Interval(TimeSpan.FromSeconds(1), scheduler).Take(4),
0,
TimeSpan.FromSeconds(2).Ticks,
TimeSpan.FromSeconds(5).Ticks);
Console.WriteLine("Time is {0} ticks", scheduler.Clock);
Console.WriteLine("Received {0} notifications", testObserver.Messages.Count);
foreach (Recorded<Notification<long>> message in testObserver.Messages)
{
Console.WriteLine("{0} @ {1}", message.Value, message.Time);
}
/*
Time is 50000000 ticks
Received 2 notifications
OnNext(0) @ 30000000
OnNext(1) @ 40000000
*/
var scheduler = new TestScheduler();
var source = scheduler.CreateColdObservable(
new Recorded<Notification<long>>(10000000, Notification.CreateOnNext(0L)),
new Recorded<Notification<long>>(20000000, Notification.CreateOnNext(1L)),
new Recorded<Notification<long>>(30000000, Notification.CreateOnNext(2L)),
new Recorded<Notification<long>>(40000000, Notification.CreateOnNext(3L)),
new Recorded<Notification<long>>(40000000, Notification.CreateOnCompleted<long>())
);
var testObserver = scheduler.Start(
() => source,
0,
0,
TimeSpan.FromSeconds(5).Ticks);
Console.WriteLine("Time is {0} ticks", scheduler.Clock);
Console.WriteLine("Received {0} notifications", testObserver.Messages.Count);
foreach (Recorded<Notification<long>> message in testObserver.Messages)
{
Console.WriteLine(" {0} @ {1}", message.Value, message.Time);
}
/*
Time is 50000000 ticks
Received 5 notifications
OnNext(0) @ 10000001
OnNext(1) @ 20000001
OnNext(2) @ 30000001
OnNext(3) @ 40000001
OnCompleted() @ 40000001
*/
var scheduler = new TestScheduler();
var source = scheduler.CreateHotObservable(
new Recorded<Notification<long>>(10000000, Notification.CreateOnNext(0L)),
new Recorded<Notification<long>>(20000000, Notification.CreateOnNext(1L)),
new Recorded<Notification<long>>(30000000, Notification.CreateOnNext(2L)),
new Recorded<Notification<long>>(40000000, Notification.CreateOnNext(3L)),
new Recorded<Notification<long>>(40000000, Notification.CreateOnCompleted<long>())
);
var testObserver = scheduler.Start(
() => source,
0,
TimeSpan.FromSeconds(1).Ticks,
TimeSpan.FromSeconds(5).Ticks);
Console.WriteLine("Time is {0} ticks", scheduler.Clock);
Console.WriteLine("Received {0} notifications", testObserver.Messages.Count);
foreach (Recorded<Notification<long>> message in testObserver.Messages)
{
Console.WriteLine(" {0} @ {1}", message.Value, message.Time);
}
/*
Time is 50000000 ticks
Received 4 notifications
OnNext(1) @ 20000000
OnNext(2) @ 30000000
OnNext(3) @ 40000000
OnCompleted() @ 40000000
*/
- RxJava
val scheduler = TestScheduler()
val expected = Arrays.asList(0L, 1L, 2L, 3L, 4L)
val result = ArrayList<Long>()
Observable
.interval(1, TimeUnit.SECONDS, scheduler)
.take(5)
.subscribe { i -> result.add(i) }
println(result.isEmpty())
scheduler.advanceTimeBy(5, TimeUnit.SECONDS)
println(result == expected)
/*
true
true
*/
val s = TestScheduler()
s.createWorker().schedule(
{ println("Immediate") })
s.createWorker().schedule(
{ println("20s") },
20, TimeUnit.SECONDS)
s.createWorker().schedule(
{ println("40s") },
40, TimeUnit.SECONDS)
println("Advancing to 1ms")
s.advanceTimeTo(1, TimeUnit.MILLISECONDS)
println("Virtual time: " + s.now(TimeUnit.SECONDS))
println("Advancing to 10s")
s.advanceTimeTo(10, TimeUnit.SECONDS)
println("Virtual time: " + s.now(TimeUnit.SECONDS))
println("Advancing to 40s")
s.advanceTimeTo(40, TimeUnit.SECONDS)
println("Virtual time: " + s.now(TimeUnit.SECONDS))
/*
Advancing to 1ms
Immediate
Virtual time: 0
Advancing to 10s
Virtual time: 10
Advancing to 40s
20s
40s
Virtual time: 40
*/
val s = TestScheduler()
s.createWorker().schedule { println("Immediate") }
s.createWorker().schedule(
{ println("20s") },
20, TimeUnit.SECONDS)
s.createWorker().schedule(
{ println("40s") },
40, TimeUnit.SECONDS)
println("Advancing by 1ms")
s.advanceTimeBy(1, TimeUnit.MILLISECONDS)
println("Virtual time: " + s.now(TimeUnit.SECONDS))
println("Advancing by 10s")
s.advanceTimeBy(10, TimeUnit.SECONDS)
println("Virtual time: " + s.now(TimeUnit.SECONDS))
println("Advancing by 40s")
s.advanceTimeBy(40, TimeUnit.SECONDS)
println("Virtual time: " + s.now(TimeUnit.SECONDS))
/*
Advancing by 1ms
Immediate
Virtual time: 0
Advancing by 10s
Virtual time: 10
Advancing by 40s
20s
40s
Virtual time: 50
*/
val s = TestScheduler()
s.createWorker().schedule { println("Immediate") }
s.createWorker().schedule(
{ println("20s") },
20, TimeUnit.SECONDS)
s.triggerActions()
println("Virtual time: " + s.now(TimeUnit.SECONDS))
/*
Immediate
Virtual time: 0
*/
val s = TestScheduler()
s.createWorker().schedule(
{ println("First") },
20, TimeUnit.SECONDS)
s.createWorker().schedule(
{ println("Second") },
20, TimeUnit.SECONDS)
s.createWorker().schedule(
{ println("Third") },
20, TimeUnit.SECONDS)
s.advanceTimeTo(20, TimeUnit.SECONDS)
/*
First
Second
Third
*/
ReactiveX 学习笔记(12)调度器的更多相关文章
- ReactiveX 学习笔记(0)学习资源
ReactiveX 学习笔记 ReactiveX 学习笔记(1) ReactiveX 学习笔记(2)创建数据流 ReactiveX 学习笔记(3)转换数据流 ReactiveX 学习笔记(4)过滤数据 ...
- Spring源码学习笔记12——总结篇,IOC,Bean的生命周期,三大扩展点
Spring源码学习笔记12--总结篇,IOC,Bean的生命周期,三大扩展点 参考了Spring 官网文档 https://docs.spring.io/spring-framework/docs/ ...
- Ext.Net学习笔记12:Ext.Net GridPanel Filter用法
Ext.Net学习笔记12:Ext.Net GridPanel Filter用法 Ext.Net GridPanel的用法在上一篇中已经介绍过,这篇笔记讲介绍Filter的用法. Filter是用来过 ...
- java之jvm学习笔记四(安全管理器)
java之jvm学习笔记四(安全管理器) 前面已经简述了java的安全模型的两个组成部分(类装载器,class文件校验器),接下来学习的是java安全模型的另外一个重要组成部分安全管理器. 安全管理器 ...
- java学习笔记13--比较器(Comparable、Comparator)
java学习笔记13--比较器(Comparable.Comparator) 分类: JAVA 2013-05-20 23:20 3296人阅读 评论(0) 收藏 举报 Comparable接口的作用 ...
- SQL反模式学习笔记12 存储图片或其他多媒体大文件
目标:存储图片或其他多媒体大文件 反模式:图片存储在数据库外的文件系统中,数据库表中存储文件的对应的路径和名称. 缺点: 1.文件不支持Delete操作.使用SQL语句删除一条记录时,对应的文 ...
- golang学习笔记12 beego table name `xxx` repeat register, must be unique 错误问题
golang学习笔记12 beego table name `xxx` repeat register, must be unique 错误问题 今天测试了重新建一个项目生成新的表,然后复制到旧的项目 ...
- Spring MVC 学习笔记12 —— SpringMVC+Hibernate开发(1)依赖包搭建
Spring MVC 学习笔记12 -- SpringMVC+Hibernate开发(1)依赖包搭建 用Hibernate帮助建立SpringMVC与数据库之间的联系,通过配置DAO层,Service ...
- muduo网络库学习笔记(五) 链接器Connector与监听器Acceptor
目录 muduo网络库学习笔记(五) 链接器Connector与监听器Acceptor Connector 系统函数connect 处理非阻塞connect的步骤: Connetor时序图 Accep ...
- Python3+Selenium3+webdriver学习笔记12(js操作应用:滚动条 日历 内嵌div)
#!/usr/bin/env python# -*- coding:utf-8 -*-'''Selenium3+webdriver学习笔记12(js操作应用:滚动条 日历 内嵌div)'''from ...
随机推荐
- [UE4]移动小地图
让玩家角色永远处于小地图的中心位置. 一.将RoundMiniMap的StaticMiniMap使用Canvas Panel包裹,StaticMiniMap的锚点Anchors设置为中心对齐 二.新建 ...
- Android知识点textview加横线的属性
textView.getPaint().setFlags(Paint. UNDERLINE_TEXT_FLAG ); //下划线 textView.getPaint().setAntiAlias(tr ...
- 如何用MAT分析Android程序的内存泄露
本文结合<Android开发艺术探索>书籍中的内存分析例子来讲解如何利用MAT工具来查找内存泄漏(以AndroidStudio开发工具为例). 1.下载MAT(Eclipse Memory ...
- Anaconda(python3.6)中使用python2.7
因为我现在安装的是最新版Anaconda3,其自带的Python版本为3.6,如果我们需要添加2.7版本的Python,可以进行如下操作.(同理,如果有人安装的是Anaconda2需要添加Python ...
- webpack、npm、nginx常用命令
webpack命令:webpack --watch 监听变动并自动打包,简写-wwebpack -p --progress --color 压缩混淆脚本webpack -d 生成映射文件,告知那些模 ...
- AFNetWorking 上传功能使用及源码分析
使用方法比较多,这里列举两种: 第一种: // 1. 使用AFHTTPSessionManager的接口 AFHTTPSessionManager *manager = [AFHTTPSessionM ...
- tp3.2 支付宝app支付
pay方法 /** *支付宝支付 */ public function pay($param) { vendor('alipay.AopSdk');// 加载类库 $config = array( ' ...
- Centos7基于容器安装运行Docker私有仓库及添加认证
一.前言 官方的Docker hub是一个用于管理公共镜像的好地方,我们可以在上面找到我们想要的镜像,也可以把我们自己的镜像推送上去.但是,有时候,我们的使用场景需要我们拥有一个私有的镜像仓库用于管理 ...
- cat & 文件结束符
语法: 连接显示 选项: -n,显示行号. -v,显示不可见打印符. -E,显示“行结束符”($). 显示行号 $ cat -n /etc/fstab /dev/VolGroup00/LogVol00 ...
- 简单方法解决bootstrap3 modal异步加载只一次的问题
用过bootstrap3自身的modal的remote属性的人可能都有相同的疑惑:就是点击弹出modal后再次点击会从缓存中加载内容,而不会再次走后台,解决办法就是只要让modal本身的属性发生变化, ...