2015-08-21 5 views
9

मैं मुसीबत मेरा कुछ डेटा की एक एनिमेटेड दृश्य बनाने FSharp.Charting और FSharp.Control.Reactive का उपयोग कर रही है पर आधारित है।चेतन चार्ट अनंत अनुक्रम

अनिवार्य रूप से, मेरे पास अंक का अनंत जनरेटर है। मेरे वास्तविक जनरेटर निम्न उदाहरण से अधिक जटिल है, लेकिन इस सरल उदाहरण समस्या reproduces:

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

यह move समारोह प्रकार (int * int) list -> seq<(int * int) list> है। यह प्रत्येक पुनरावृत्ति के लिए इनपुट सूची में सभी बिंदुओं का अनुवाद करता है, ताकि अंक ऊपर और दाईं ओर बढ़ जाए।

मैं इसे LiveChart.Point पर दिखाना चाहता हूं। move द्वारा उत्पन्न अनुक्रम एक उपयुक्त Observable करने के लिए परिवर्तित किया जा सकता है, लेकिन अपने आप में यह काफी तेज़ी से चलता है, तो मैं पहले इसे नीचे थोड़ा धीमा:

// 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 # इंटरएक्टिव (FSI) पर भेजते हैं, तो यह प्रिंटिंग रखता है, और आपको मूल्यांकन को रद्द करना होगा या इसे रोकने के लिए सत्र को रीसेट करना होगा।

मेरा सिद्धांत यह है कि ऐसा इसलिए है क्योंकि obs निष्पादन वातावरण के समान थ्रेड पर चल रहा है।

एक ही होता है अगर मैं एक LiveChart.Point इसे से बाहर बनाने की कोशिश: और FSI ब्लॉक

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

अगर मैं FSI को यह भेजने के लिए, कुछ नहीं होता (कोई चार्ट दिखाया गया है),।

यह मेरे सिद्धांत के अनुरूप लगता है कि पर्यवेक्षक चार्ट के समान धागे पर चल रहा है।

मैं ऑब्जर्वर को एक अलग थ्रेड पर कैसे चला सकता हूं?

मैंने Observable.observeOn खोजा है, जो IScheduler लेता है। ब्राउज़िंग एमएसडीएन, मैंने NewThreadScheduler, ThreadPoolScheduler, और TaskPoolScheduler की खोज की है, जिनमें से सभी IScheduler लागू करते हैं। इन वर्गों के नाम वादा करने वाले ध्वनि हैं, लेकिन मैं उन्हें नहीं ढूंढ सकता!

प्रलेखन के अनुसार, वे सभी System.Reactive.dll में परिभाषित हैं, लेकिन जब मेरे पास FSharp.Control.Reactive की सभी निर्भरताएं हैं, तो मेरे पास उस असेंबली कहीं भी नहीं है। इंटरनेट खोजना यह नहीं पता है कि इसे कहां प्राप्त किया जाए, या तो।

क्या यह प्रतिक्रियाशील एक्सटेंशन का पुराना या नया संस्करण है? क्या मैं सही दिशा में भी देख रहा हूं?

मैं LiveChart पर अपने अनंत अनुक्रमों को कैसे देख सकता हूं?

#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} 

उत्तर

6

चाल का उपयोग करने के लिए है subscribeOn। subscribeOn पर introtorx.com और observeOn से:

एक ख़तरा मैं यहाँ का कहना है करने के लिए है चाहता हूँ, पहले कुछ समय मैं इन भार के लिए प्रयोग किया जाता है, मैं क्या वे वास्तव में क्या करने के लिए के रूप में उलझन में था। आपको यह भी वर्णन करने के लिए सदस्यताऑन विधि का उपयोग करना चाहिए कि आप कैसे गर्मजोशी और पृष्ठभूमि प्रसंस्करण कोड निर्धारित करना चाहते हैं। उदाहरण के लिए, यदि आप Observable.Create के साथ सदस्यताऑन का उपयोग करना चाहते थे, तो निर्माण विधि को पास किया गया प्रतिनिधि निर्दिष्ट शेड्यूलर पर चलाया जाएगा।

ObserveOn विधि का उपयोग यह घोषित करने के लिए किया जाता है कि आप अपनी सूचनाओं को कहां निर्धारित करना चाहते हैं। मैं सुझाव दूंगा कि एसटीए सिस्टम के साथ काम करते समय ObserveOn विधि सबसे उपयोगी है, आमतौर पर यूआई अनुप्रयोग।

पूरा नीचे स्क्रिप्ट:

#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() 
एक यूआई आवेदन आप subscribeOn और observeOn जोड़ी परिणाम सुनिश्चित करने के हैं में

आमतौर पर यूआई धागे पर वापस जा रहे हैं। ऐसा लगता है कि चार्ट की आवश्यकता नहीं है क्योंकि ऐसा लगता है कि चार्ट आपके लिए यह संभालता है (मेरे लिए काम करता है)।

1

Schedulers System.Reactive.PlatformServices.dll में परिभाषित कर रहे हैं (जो द्वारा स्थापित किया गया है आरएक्स-प्लेटफार्म सर्विसेज पैकेज)।

मैं उन्हें यहाँ मिल गया है: https://github.com/Reactive-Extensions/Rx.NET/tree/master/Rx.NET/Source/System.Reactive.PlatformServices/Reactive/Concurrency

उदाहरण नई थ्रेड समयबद्धक का उपयोग करने के लिए: (नमूदार) .ObserveOn (System.Reactive.Concurrency.NewThreadScheduler.Default)

+0

यह वास्तव में अजीब है, लेकिन यह मेरी मशीन पर नहीं है ... अगर मैं प्रतिबिंबक के साथ 'System.Reactive.Core.dll' खोलता हूं, तो' System.Reactive.Concurrency' नामस्थान में कोई 'न्यू थ्रेडशेड्यूलर' श्रेणी नहीं है .. साथ ही, 'System.Reactive.Concurrency.NewThreadScheduler.Default' संकलित नहीं करता है ... मुझे * त्रुटि FS0039 मिलती है: मान, कन्स्ट्रक्टर, नेमस्पेस या टाइप' न्यू थ्रेडशेड्यूलर 'परिभाषित नहीं किया गया है *। –

+0

आह, इसलिए यह आरएक्स-प्लेटफार्म सर्विसेज होना चाहिए जिसमें शेड्यूलर शामिल हों। –

+0

+1 वे * आरएक्स-प्लेटफार्म सेवा * में हैं। दुर्भाग्यवश, वादा करने वाले नामों के साथ शेड्यूलर में से कोई भी मेरी समग्र समस्या को हल करने लगता है ... –

संबंधित मुद्दे