c# - 基于推和拉的结构(如 IEnumerable)有什么区别和 IObservable
问题描述
在每一次技术演讲或每篇关于IEnumerable和IObservable的博客文章中,我都读到, IEnumerable是基于拉的结构,而 IObservable是基于推的结构。
我读过IObservable我们有异步调用,没有任何东西被阻塞,一切都是基于推送的。
但是,但是,但是……
它的真正含义是什么?基于推送和基于拉取
因为在我看来,在IEnumerable中,我们还可以将数据推送到结构中并从中提取数据,所以我真的迷失了那些技术术语和想法。
请以正常和人性化的方式向我解释这两种结构之间的区别以及基于推和基于拉的结构之间的区别。
谢谢。
解决方案
请以正常和人性化的方式向我解释其中的区别
好吧,让我们烤些面包吧。这是我做的最正常的人类行为。
基于拉取:
// I want some toast. I will pull it out of the toaster when it is done.
// I will do nothing until the toast is available.
Toast t = toaster.MakeToast();
t.AddJam();
// Yum.
基于推送:
// I want some toast. But it might take a while and I can do more work
// while I am waiting:
Task<Toast> task = toaster.MakeToastAsync();
Toast t = await task;
// await returns to the caller if the toast is not ready, and assigns
// a callback. When the toast is ready, the callback causes this method
// to start again from this point:
t.AddJam();
// Yum.
你想提取一个结果,你调用一个函数,在函数返回之前你什么都不做。
你想要一个结果推送给你,你调用一个异步函数并等待结果。当结果可用时,它被推送到回调中,它会在需要的地方恢复方法。
IEnumerable<T>
只是一系列的拉动;MoveNext
每次你想得到一个结果时你都会打电话,你会得到一个T
. IObservable<T>
只是一系列的推动;你注册一个回调,每次有新T
的可用时都会调用它。
换句话说: IEnumerable<T>
逻辑上是一系列Func<T>
调用。 IObservable<T>
逻辑上是一个Task<T>
连续的序列。不要让它们是序列的事实使您感到困惑;那是偶然的。基本思想是函数是同步的;您调用它们并同步获得结果;如果需要一段时间,你就等。任务是异步的;您启动它们并在可用时异步获取结果。
这个想法在 C# 之前IObservable
和await
. 另一种看待方式是:pull-based 就像函数调用,push-based 就像事件处理程序。一个普通的函数调用,当你想要什么时调用它。一个事件处理程序,当有事情发生时它会调用你。 事件是 C# 语言本身表示观察者模式的方式。但是事件总是在逻辑上形成一个序列,因此能够像操作一系列拉取项一样操作一系列推送项是有意义的。因此,IObservable
被发明了。
推荐阅读
- javascript - 有没有办法为 ES5.1 类分配一个匿名函数?
- node.js - 带有 react 的 Django 或带有 react 的 node js 将来会有更多的空缺
- reactjs - React / Web3:componendDidMount 和 Function 中的不同行为
- sql - 告诉我这个简单的 SQL 代码中的错误在哪里
- python - 如果游戏最后被 time.sleep() 冻结,我应该在哪里放置重启和退出按钮?
- c# - 无法使用 AAD/Microsoft-Identity id_token 上的 System.IdentityModel.Tokens.Jwt 库验证签名
- javascript - 我对 datepicker dateDisnable 有问题
- python - pygame窗口不加载填充
- java - 在 Java 中将枚举序列化为 JSON
- r - bnlearn 错误:条件概率分布的数量错误