我有一个静态集合,比如调用远程休息api的任务:
static ConcurrentBag<Task<HttpResponseMessage>> _collection = new ConcurrentBag<Task<HttpResponseMessage>>();
static void Main(string[] args)
{
Task.Factory.StartNew(() => Produce());
Task.Factory.StartNew(() => Consume());
Console.ReadKey();
}
一个线程在其中添加新项目:
private static void Produce()
{
while (true)
{
var task = HttpClientFactory.Create().GetAsync("http://example.com");
_collection.Add(task);
Thread.Sleep(500);
}
}
另一个线程应该处理这些项目:
private static void Consume()
{
_collection.ToObservable()
.Subscribe(
t => Console.WriteLine("++"),
ex => Console.WriteLine(ex.Message),
() => Console.WriteLine("Done"));
}
但它只运行一次并过早完成。所以输出是;
++
完成
答案 0 :(得分:4)
如果它像那样工作会很有趣......但遗憾的是它并没有。 ToObservable
扩展方法是在IEnumerable<T>
界面上定义的 - 因此它可以获得该集合的时间点快照。
您需要一个可以观察到的集合,例如ObservableCollection。通过这种方式,您可以响应添加事件以提供Rx管道(可能通过CollectionChanged
事件连接Observable.FromEventPattern
事件。请记住,此集合不支持并发添加。这种技术是进入monad&#34;的一种方式。 (即获得IObservable<T>
)。
等效于将您的请求有效负载添加到主题。无论哪种方式,您都可以将它们投射到异步请求中。所以说(为了论证),你的Produce
签名看起来像这样:
private static async Task<HttpResponseMessage> Produce(string requestUrl)
然后你可以使用你的Produce
方法构造一个observable来将requestUrls转换为异步Web请求,如下所示:
var requests = new Subject<string>();
var responses = requests.SelectMany(
x => Observable.FromAsync(() => Produce(x)));
responses.Subscribe(
t => Console.WriteLine("++"),
ex => Console.WriteLine(ex.Message),
() => Console.WriteLine("Done"));
并提交每个请求,例如:
requests.OnNext("http://myurl");
如果您需要并发添加,请参阅Observable.Synchronize。
如果您需要控制处理响应的线程,请使用ObserveOn
,我写了here的冗长解释。