我们有一个通知数据更改的来源,当项目进入时我们异步获取新数据。
source.SelectMany(async n => { await FetchData()});
在等待加载数据的同时,许多通知可能会进入,但我们希望忽略除1之外的所有通知,这样我们就不会为每个通知获取数据,而是再次只进行一次。
除了1之外,我们怎样才能忽略来自源的所有通知,直到获取数据为止?
我感觉解决方案将涉及将FetchData()转换为IObservable,但我仍然不知道Rx原语允许我们组合流。
答案 0 :(得分:1)
看起来像一个非常经典(但缺失)的Rx运算符的用例:ObserveLatestOn
(示例实现here,但您可以在网上找到其他人)。
source.ObserveLatestOn(TimeSpan.Zero, Schedulers.NewThread).SelectMany(async n => { await FetchData()})
请注意,此实现仅在单线程调度程序上进行了测试(主要是UI,但可以使用NewThread),而不是使用Immediate
/ CurrentThread
(可能有效)或TaskPool
(可能有竞争条件)
另请注意,您在此处遇到的是Rx.Net中缺乏反应性拉backpressure(在讨论here中),RxJava对这种情况有很好的背压支持(例如{{ 3}})
答案 1 :(得分:0)
我确信有一种方法可以使用Rx,但我想到的一个简单的解决方案是使用AsyncAutoResetEvent(AutoResetEvent的异步版本)。
基本上,您创建一个异步等待的循环,以便设置AsyncAutoResetEvent,这在收到新通知时完成。自动重置确保在下次等待时,您将被异步阻止,直到收到新通知。
您可以在Stephen Cleary AsyncEx创建的优秀库中找到AsyncAutoResetEvent类作为Nuget包。
这是一个简单的程序,显示了提议的解决方案:
class Program
{
static readonly AsyncAutoResetEvent _resetEvent = new AsyncAutoResetEvent();
static void Main(string[] args)
{
// Start the asynchronous fetching loop...
RunAsync();
Task.Run(async () =>
{
// Simulate fast notifications
for (int i = 0; i < 15; i++)
{
OnNotification(i);
await Task.Delay(100);
}
// Simulate a pause of notifications
await Task.Delay(2000);
// Simulate fast notifications
for (int i = 0; i < 15; i++)
{
OnNotification(i);
await Task.Delay(100);
}
});
Console.ReadKey();
}
static void OnNotification(int index)
{
Console.WriteLine(DateTime.Now.ToLongTimeString() + " OnNotification " + index);
// This will unlock the current or next WaitAsync on the _resetEvent
_resetEvent.Set();
}
static async Task RunAsync()
{
// Uncomment this if you want to wait for a first notification before fetching.
// await _resetEvent.WaitAsync();
while (true)
{
Console.WriteLine(DateTime.Now.ToLongTimeString() + " Fetching...");
// Simulate long fetching
await Task.Delay(1000);
// Wait for a new notification before doing another fetch
await _resetEvent.WaitAsync();
}
}
}
这是输出:
12:04:51 PM Fetching...
12:04:51 PM OnNotification 0
12:04:52 PM OnNotification 1
12:04:52 PM OnNotification 2
12:04:52 PM OnNotification 3
12:04:52 PM OnNotification 4
12:04:52 PM OnNotification 5
12:04:52 PM OnNotification 6
12:04:52 PM OnNotification 7
12:04:52 PM OnNotification 8
12:04:52 PM OnNotification 9
12:04:52 PM Fetching...
12:04:53 PM OnNotification 10
12:04:53 PM OnNotification 11
12:04:53 PM OnNotification 12
12:04:53 PM OnNotification 13
12:04:53 PM OnNotification 14
12:04:53 PM Fetching...
12:04:55 PM OnNotification 0
12:04:55 PM Fetching...
12:04:55 PM OnNotification 1
12:04:55 PM OnNotification 2
12:04:55 PM OnNotification 3
12:04:56 PM OnNotification 4
12:04:56 PM OnNotification 5
12:04:56 PM OnNotification 6
12:04:56 PM OnNotification 7
12:04:56 PM OnNotification 8
12:04:56 PM OnNotification 9
12:04:56 PM Fetching...
12:04:56 PM OnNotification 10
12:04:56 PM OnNotification 11
12:04:56 PM OnNotification 12
12:04:57 PM OnNotification 13
12:04:57 PM OnNotification 14
12:04:57 PM Fetching...