Warning: file_get_contents(/data/phpspider/zhask/data//catemap/4/fsharp/3.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
F# 基于无限序列的可观测动态图表_F#_System.reactive_Fsharpchart - Fatal编程技术网

F# 基于无限序列的可观测动态图表

F# 基于无限序列的可观测动态图表,f#,system.reactive,fsharpchart,F#,System.reactive,Fsharpchart,使用FSharp.Charting和FSharp.Control.Reactive创建我的一些数据的动画可视化时遇到问题 本质上,我有一个无限的点生成器。我的真实生成器比下面的示例更复杂,但这个简化示例再现了这个问题: let move points = Seq.initInfinite (fun i -> points |> List.map (fun (x, y) -> x + i, y + i)) 此move函数具有类型(int*int)list->seq。对于

使用FSharp.ChartingFSharp.Control.Reactive创建我的一些数据的动画可视化时遇到问题

本质上,我有一个无限的点生成器。我的真实生成器比下面的示例更复杂,但这个简化示例再现了这个问题:

let move points =
    Seq.initInfinite (fun i -> points |> List.map (fun (x, y) -> x + i, y + i))
move
函数具有类型
(int*int)list->seq
。对于每次迭代,它将输入列表中的所有点平移1,以便点向上和向右移动

我想在
LiveChart.Point
上显示这一点。由
move
生成的序列可以转换为适当的
可观察的
,但其本身运行速度相当快,因此我首先将其减慢一点:

// Slow down any sequence
let delay (duration : TimeSpan) xs = seq {
    for x in xs do
    duration.TotalMilliseconds |> int |> Async.Sleep |> Async.RunSynchronously
    yield x }
这使我能够从点序列中创建一个可观察的点:

let obs =
    [(1, 0); (0, 1)]
    |> move
    |> delay (TimeSpan.FromSeconds 0.5)
    |> Observable.toObservable
我还可以看到,如果我打印到控制台,它可以工作:

obs.Subscribe (fun x -> printfn "%O" x)
通过打印到控制台,很明显这会阻塞执行环境;例如,如果您将脚本发送到F#Interactive(FSI),它将继续打印,您必须取消评估或重置会话才能停止它

我的理论是,这是因为
obs
与执行环境运行在同一个线程上

如果我尝试制作一个
LiveChart,也会发生同样的情况。从中指出:

let lc = obs |> LiveChart.Point
lc.ShowChart()
如果我把这个发送给FSI,什么也不会发生(没有显示图表),FSI会阻塞

这似乎与我的理论一致,即观察者与图表运行在同一条线上

如何使观察者在不同的线程上运行?

我发现了
可观察的.observeOn
,它需要一个
IScheduler
。浏览MSDN,我发现了,并且,所有这些都实现了
IScheduler
。这些类的名称听起来很有希望,但我找不到它们

根据文档,它们都是在
System.Reactive.dll
中定义的,但是尽管我有的所有依赖项,但我在任何地方都没有该程序集。搜索互联网也没有透露在哪里可以找到它

它是旧版本还是新版本的被动扩展?我看的方向对吗

我如何在
动态图表
上可视化我的无限点序列


以下是重现该问题的完整脚本:

#r @"../packages/Rx-Interfaces.2.2.5/lib/net45/System.Reactive.Interfaces.dll"
#r @"../packages/Rx-Core.2.2.5/lib/net45/System.Reactive.Core.dll"
#r @"../packages/Rx-Linq.2.2.5/lib/net45/System.Reactive.Linq.dll"
#r @"../packages/FSharp.Control.Reactive.3.2.0/lib/net40/FSharp.Control.Reactive.dll"
#r @"../packages/FSharp.Charting.0.90.12/lib/net40/FSharp.Charting.dll"
#r "System.Windows.Forms.DataVisualization"

open System
open FSharp.Control.Reactive
open FSharp.Charting

let move points =
    Seq.initInfinite (fun i -> points |> List.map (fun (x, y) -> x + i, y + i))

// Slow down any sequence
let delay (duration : TimeSpan) xs = seq {
    for x in xs do
    duration.TotalMilliseconds |> int |> Async.Sleep |> Async.RunSynchronously
    yield x }

let obs =
    [(1, 0); (0, 1)]
    |> move
    |> delay (TimeSpan.FromSeconds 0.5)
    |> Observable.toObservable

//obs.Subscribe (fun x -> printfn "%O" x)

let lc = obs |> LiveChart.Point
lc.ShowChart()
已安装的NuGet软件包:

Id                                  Versions
--                                  --------
FSharp.Charting                     {0.90.12}
FSharp.Control.Reactive             {3.2.0}
FSharp.Core                         {3.1.2}
Rx-Core                             {2.2.5}
Rx-Interfaces                       {2.2.5}
Rx-Linq                             {2.2.5}

调度器在System.Reactive.PlatformServices.dll(由Rx PlatformServices包安装)中定义

我在这里找到了它们:


例如,要使用新的线程调度程序:(observable).ObserveOn(System.Reactive.Concurrency.NewThreadScheduler.Default)

诀窍是使用subscribeOn。 从订阅到观察:

我想在这里指出的一个陷阱是,最初几次我使用这些重载时,我对它们的实际用途感到困惑。您应该使用SubscribeOn方法来描述您希望如何安排任何预热和后台处理代码。例如,如果将SubscribeOn与Observable.Create一起使用,则传递给Create方法的委托将在指定的调度程序上运行

ObserveOn方法用于声明您希望将通知安排到的位置。我认为ObserveOn方法在使用STA系统(最常见的UI应用程序)时最有用

完成以下脚本:

#r @"packages/Rx-Interfaces.2.2.5/lib/net45/System.Reactive.Interfaces.dll"
#r @"packages/Rx-PlatformServices.2.2.5/lib/net45/System.Reactive.PlatformServices.dll"
#r @"packages/Rx-Core.2.2.5/lib/net45/System.Reactive.Core.dll"
#r @"packages/Rx-Linq.2.2.5/lib/net45/System.Reactive.Linq.dll"
#r @"packages/FSharp.Control.Reactive.3.2.0/lib/net40/FSharp.Control.Reactive.dll"
#r @"packages/FSharp.Charting.0.90.12/lib/net40/FSharp.Charting.dll"
#r "System.Windows.Forms.DataVisualization"

open System
open FSharp.Control.Reactive
open FSharp.Charting
open System.Reactive.Concurrency

let move points =
    Seq.initInfinite (fun i -> points |> List.map (fun (x, y) -> x + i, y + i))

// Slow down any sequence
let delay (duration : TimeSpan) xs = seq {
    for x in xs do
    duration.TotalMilliseconds |> int |> Async.Sleep |> Async.RunSynchronously
    yield x }

let obs =
    [(1, 0); (0, 1)]
    |> move
    |> delay (TimeSpan.FromSeconds 0.5)
    |> Observable.toObservable
    |> Observable.subscribeOn NewThreadScheduler.Default 

let lc = obs |> LiveChart.Point
lc.ShowChart()

通常在UI应用程序中,您会将subscribeOn和observeOn配对,以确保结果返回到UI线程上。这里似乎不需要它,因为它看起来像是图表为您处理的(对我有效)。

这真的很奇怪,但它不在我的机器上。。。如果我用Reflector打开
System.Reactive.Core.dll
,则
System.Reactive.Concurrency
命名空间中没有
NewThreadScheduler
类。。。另外,
System.Reactive.Concurrency.NewThreadScheduler.Default
不编译。。。我收到错误FS0039:未定义值、构造函数、命名空间或类型“NewThreadScheduler”。啊,因此必须是Rx PlatformServices,然后它包含调度器。+1它们在Rx PlatformServices中。不幸的是,没有一个名字很有前途的调度器能够解决我的总体问题。。。