You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
With a little effort, we were able to adapt `IObservable<'a>` to our needs. Next let's try implementing the storage of
232
-
filtered tweets. Again, we can adapt the function `storeTweet` defined above to the observable model and bind the
233
-
observable of filtered tweets to it:
234
-
*)
235
-
236
-
letstoredTweetsObs:IObservable<unit>=
237
-
filteredTweetsObs'
238
-
|> Observable.mapAsync storeTweet
239
-
240
-
(**
241
-
The observable sequence `storedTweetsObs` will produces a value each time a filtered tweet is stored. The entire
242
-
workflow can be expressed as follows:
243
-
*)
244
-
245
-
letstoredTeetsObs' :IObservable<unit>=
246
-
tweetsObs
247
-
|> Observable.filterAsync filterTweet
248
-
|> Observable.mapAsync storeTweet
249
-
250
-
(**
251
-
Overall, both solutions are succinct and composable and deciding which one to use can ultimately be a matter of preference.
252
-
Some things to consider are the "synchronous push" vs. "asynchronous pull" semantics. On the one hand, tweets are pushed based - the consumer has no control
253
-
over their generation. On the other hand, the program at hand will process the tweets on its own terms regardless of how quickly
254
-
they are being generated. Moreover, the underlying Twitter API will likely utilize a request-reply protocol to retrieve batches of
255
-
tweets from persistent storage. As such, the distinction between "synchronous push" vs. "asynchronous pull" becomes less interesting. If the underlying source
256
-
is truly push-based, then one can buffer its output and consume it using an asynchronous sequence. If the underlying source is pull-based,
257
-
then one can turn it into an observable sequence by first pulling, then pushing. Note however that in a true real-time reactive system,
258
-
notifications must be pushed immediately without delay.
259
-
260
-
Upon closer inspection, the consumption approaches between the two models aren't all too different. While `AsyncSeq` is based on an asynchronous-pull operation,
261
-
it is usually consumed using an operator such as `AsyncSeq.iterAsync` as shown above. This is a function of type
262
-
`('T -> Async<unit>) -> AsyncSeq<'T> -> Async<unit>` where the first argument is a function `'T -> Async<unit>` which performs
263
-
some work on an item of the sequence and is applied repeatedly to subsequent items. In a sense, `iterAsync`*pushes* values to this
264
-
function. The primary difference from observers of observable sequences is the return type `Async<unit>` rather than simply `unit`.
265
-
266
155
### Performance Considerations
267
156
268
157
While an asynchronous computation obviates the need to block an OS thread for the duration of an operation, it isn't always the case
0 commit comments