我有以下要求:
这是一个非常简化的流程,真正的流程也必须处理错误,还有其他方面,我认为这与我的问题无关,或者它似乎暂时无关。
无论如何,这是我如何实现所描述的流程:
var data = await GetSitesSource()
.Select(site => Observable
.FromAsync(() => GetInformationFromSiteAsync(site))
.Select(site.MakeKeyValuePair))
.Merge(maxConcurrentSiteRequests)
.ToList();
if (data.Count > 0)
{
var filePath = GetFilePath();
using (var w = new StreamWriter(filePath))
{
await w.WriteAsync(YieldLines(data));
}
var tsUTC = DateTime.UtcNow;
await data.ToObservable()
.Select(o => Observable.FromAsync(() => AckInformationFromSiteAsync(o.Key, tsUTC, o.Value.InformationId)))
.Merge(maxConcurrentSiteRequests);
}
其中:
MakeKeyValuePair
是一种返回KeyValuePair<K,V>
实例YieldLines
将data
转换为IEnumerable<string>
WriteAsync
是一种虚构的扩展方法,将一系列字符串写入其StreamWriter
这似乎不是一个好的实现,因为我没有利用这个事实,即我可以在第一个Merge
运算符出来时开始写出记录。
我可以使用SelectMany
+ Merge(1)
运算符异步写出文件的块(顺序无关紧要),但是如何确保相应的StreamWriter
被初始化只在需要时才妥善处理?因为如果没有数据,我甚至不想初始化StreamWriter
。
我的问题 - 如何重写此代码,以便Observable管道在中间不会被中断以写出文件?它应包括所有三个阶段:
答案 0 :(得分:1)
我还没有对此进行过测试,但是您的代码都没有阻止它们加入。所以你可以这样做:
//The ToObservable extension for Task is only available through
using System.Reactive.Threading.Tasks;
GetSitesSource()
.Select(site => Observable
.FromAsync(() => GetInformationFromSiteAsync(site))
.Select(site.MakeKeyValuePair))
.Merge(maxConcurrentSiteRequests)
.ToList()
//Only proceed if we received data
.Where(data => data.Count > 0)
.SelectMany(data =>
//Gives the StreamWriter the same lifetime as this Observable once it subscribes
Observable.Using(
() => new StreamWriter(GetFilePath()),
(w) => w.WriteAsync(YieldLines(data)).ToObservable()),
//We are interested in the original data value, not the write result
(data, _) => data)
//Attach a timestamp of when data passed through here
.Timestamp()
.SelectMany(o=> {
var ts = o.Timestamp;
var data= o.Value;
//This is actually returning IEnumerable<IObservable<T>> but merge
//will implicitly handle it.
return data.Select(i => Observable.FromAsync(() =>
AckInformationFromSiteAsync(i.Key, ts,
i.Value.InformationId)))
.Merge(maxConcurrentSiteRequests);
})
//Handle the return values, fatal errors and the completion of the stream.
.Subscribe();
更全面地回答您的问题
Using
运算符将必须实现IDisposable
的资源绑定到Observable的生命周期。第一个参数是一个工厂函数,当Observable订阅时将调用一次。