के संबंध में एएसआईसीसी-प्रतीक्षा सी # कोड को एफ # में अनुवाद करना मुझे आश्चर्य है कि यह एक व्यापक सवाल है, लेकिन हाल ही में मैंने खुद को कोड के एक टुकड़े में आने के लिए बनाया है, मैं इस बारे में निश्चित होना चाहता हूं कि कैसे अनुवाद करना है सी # उचित एफ # में। यात्रा here (1) (टीपीएल-एफ # इंटरैक्शन के साथ मूल समस्या) से शुरू होती है, और here (2) जारी है (कुछ उदाहरण कोड मैं एफ # में अनुवाद करने पर विचार कर रहा हूं)।शेड्यूलर
उदाहरण कोड यहां पुन: उत्पन्न करने के लिए बहुत लंबा है, लेकिन दिलचस्प कार्य ActivateAsync
, RefreshHubs
और AddHub
हैं। विशेष रूप से दिलचस्प अंक
AddHub
काprivate async Task AddHub(string address)
का हस्ताक्षर है।RefreshHubs
एक पाश मेंAddHub
कॉल औरtasks
की एक सूची है, जो यह तोawait Task.WhenAll(tasks)
से बहुत अंत में इंतजार कर रहा है और इसके परिणामस्वरूप वापसी मानprivate async Task RefreshHubs(object _)
के अपने हस्ताक्षर से मेल खाता है एकत्र करता है।RefreshHubs
ActivateAsync
द्वाराawait RefreshHubs(null)
के रूप में जाना जाता है और फिर अंत मेंawait base.ActivateAsync()
पर कॉल हस्ताक्षरpublic override async Task ActivateAsync()
से मेल खाता है।
प्रश्न:
क्या एफ # है कि अभी भी इंटरफ़ेस और कार्यक्षमता को बनाए रखता है और डिफ़ॉल्ट, कस्टम अनुसूचक का सम्मान करता है करने के लिए इस तरह के समारोह हस्ताक्षर के सही अनुवाद हो सकता है? और मैं अन्यथा इस बारे में भी निश्चित नहीं हूं कि "async/f # में प्रतीक्षा करें" या तो। इसे "यांत्रिक रूप से" कैसे करें। :)
कारण यह है कि "यहां (1)" लिंक में समस्या है (मैंने यह सत्यापित नहीं किया है) कि F # async संचालन में एक कस्टम, सहकारी शेड्यूलर (ऑरलियन्स) द्वारा सेट नहीं किया गया है) रनटाइम। इसके अलावा, यह here कहा गया है कि टीपीएल ऑपरेशंस शेड्यूलर से बचते हैं और टास्क पूल पर जाते हैं और इसलिए उनका उपयोग प्रतिबंधित है। इस प्रकार
//Sorry for the inconvenience of shorterned code, for context see the link "here (1)"...
override this.ActivateAsync() =
this.RegisterTimer(new Func<obj, Task>(this.FlushQueue), null, TimeSpan.FromMilliseconds(100.0), TimeSpan.FromMilliseconds(100.0)) |> ignore
if RoleEnvironment.IsAvailable then
this.RefreshHubs(null) |> Async.awaitPlainTask |> Async.RunSynchronously
else
this.AddHub("http://localhost:48777/") |> Async.awaitPlainTask |> Async.RunSynchronously
//Return value comes from here.
base.ActivateAsync()
member private this.RefreshHubs(_) =
//Code omitted, in case mor context is needed, take a look at the link "here (2)", sorry for the inconvinience...
//The return value is Task.
//In the C# version the AddHub provided tasks are collected and then the
//on the last line there is return await Task.WhenAll(newHubAdditionTasks)
newHubs |> Array.map(fun i -> this.AddHub(i)) |> Task.WhenAll
member private this.AddHub(address) =
//Code omitted, in case mor context is needed, take a look at the link "here (2)", sorry for the inconvinience...
//In the C# version:
//...
//hubs.Add(address, new Tuple<HubConnection, IHubProxy>(hubConnection, hub))
//}
//so this is "void" and could perhaps be Async<void> in F#...
//The return value is Task.
hubConnection.Start() |> Async.awaitTaskVoid |> Async.RunSynchronously
TaskDone.Done
startAsPlainTask
समारोह here से साचा नाई से है
एक तरह से मैं इस के साथ काम कर के बारे में सोच सकते हैं एक एफ # समारोह के साथ है। मैं सिर्फ Task.WhenAll
भी प्रतीक्षा कर रहे थे करने की आवश्यकता होगी देखा: एक और दिलचस्प विकल्प here रूप
module Async =
let AwaitTaskVoid : (Task -> Async<unit>) =
Async.AwaitIAsyncResult >> Async.Ignore
< संपादित हो सकता है। लेकिन सही तरीका क्या होगा? उह, समय (एक बुरा यमक) सोने के लिए ...
< संपादित 2:here (1) पर (के साथ मूल समस्या TPL-एफ # बातचीत) Codeplex में यह उल्लेख किया गया था कि एफ # तुल्यकालन संदर्भों का उपयोग करता धागे के काम पुश करने के लिए , जबकि टीपीएल नहीं करता है। अब, यह एक व्यावहारिक स्पष्टीकरण है, मुझे लगता है (हालांकि कस्टम शेड्यूलर के बावजूद मुझे इन स्निपेट्स को सही ढंग से अनुवाद करने में समस्याएं हैं)।कुछ रोचक अतिरिक्त जानकारी से
- How to get a Task that uses SynchronizationContext? And how are SynchronizationContext used anyway?
- Await, SynchronizationContext, and Console Apps था जिसमें एक उदाहरण
SingleThreadSynchronizationContext
प्रदान की जाती है कि कतारों की तरह काम लग रहा है निष्पादित करने के लिए हो सकता है। शायद इसका इस्तेमाल किया जाना चाहिए?
मुझे लगता है मैं इस संदर्भ में Hopac उल्लेख करना होगा, एक दिलचस्प स्पर्शरेखा के रूप में लगता है और यह भी मैं अगले 50 अजीब घंटे या तो मामले में अपने सभी पार पोस्टिंग हाथ से जाने के लिए पहुंच से बाहर कर रहा हूँ का उल्लेख है।
< संपादित 3: Daniel और svick टिप्पणी में अच्छी सलाह एक कस्टम कार्य निर्माता का उपयोग करना दे। डैनियल एक ऐसे लिंक को प्रदान करता है जो पहले ही FSharpx में परिभाषित है।
स्रोत मैं देख रहा हूँ मानकों के साथ इंटरफेस
type TaskBuilder(?continuationOptions, ?scheduler, ?cancellationToken) =
let contOptions = defaultArg continuationOptions TaskContinuationOptions.None
let scheduler = defaultArg scheduler TaskScheduler.Default
let cancellationToken = defaultArg cancellationToken CancellationToken.None
यदि एक ऑरलियन्स में इस का उपयोग करने के लिए गए थे के रूप में परिभाषित कर रहे हैं को देखते हुए, यह TaskScheduler
की तरह लग रहा TaskScheduler.Current
प्रति प्रलेखन के रूप में होना चाहिए here
ऑरलियन्स का अपना कार्य शेड्यूलर है जो अनाज के भीतर उपयोग किए गए एकल थ्रेडेड निष्पादन मॉडल प्रदान करता है। यह महत्वपूर्ण है कि कार्य करते समय ऑरलियन्स शेड्यूलर का उपयोग किया जाता है, न कि .NET थ्रेड पूल।
अपने अनाज कोड की आवश्यकता है एक उपकार्य बनाया जाना है, तो आप Task.Factory.StartNew उपयोग करना चाहिए:
का इंतजार Task.Factory.StartNew (() => {/ * तर्क * /});
यह तकनीक वर्तमान कार्य शेड्यूलर का उपयोग करेगी, जो ऑरलियन्स शेड्यूलर होगी।
आपको टास्क.रुन का उपयोग करने से बचना चाहिए, जो हमेशा .NET थ्रेड पूल का उपयोग करता है, और इसलिए सिंगल-थ्रेडेड निष्पादन मॉडल में नहीं चलाया जाएगा।
ऐसा लगता है कि TaskScheduler.Current और TaskScheduler.Default के बीच एक सूक्ष्म अंतर है। हो सकता है कि यह एक प्रश्न पूछता है जिसमें उदाहरण के मामलों में एक अवांछित अंतर होगा। ऑरलियन्स प्रलेखन बताते Task.Run
उपयोग करने के लिए नहीं है और इसके बजाय Task.Factory.StartNew
के लिए गाइड के रूप में, मुझे आश्चर्य है अगर एक के रूप में के रूप में Task.Run vs Task.Factory.StartNew पर स्टीफन Toub और StartNew is Dangerous पर स्टीफन Cleary इस तरह के अधिकारियों द्वारा की सिफारिश की है TaskCreationOptions.DenyAttachChild को परिभाषित करना चाहिए। हम्म, ऐसा लगता है कि .Default
.DenyAttachChilld
होगा जब तक कि मैं गलत नहीं हूं।
इसके अलावा, के रूप में वहाँ Task.Run
Task.Factory.CreateNew
अर्थात कस्टम अनुसूचक के बारे में के साथ एक समस्या है, मुझे आश्चर्य है अगर इस विशेष समस्या एक कस्टम TaskFactory रूप Task Scheduler (Task.Factory) and controlling the number of threads और How to: Create a Task Scheduler That Limits Concurrency में विस्तार से बताया उपयोग करके हटाया जा सकता है।
हम्म, यह पहले से ही काफी लंबे समय से "लंदन" बन रहा है। मुझे आश्चर्य है कि मुझे इसे कैसे बंद करना चाहिए?हो सकता है कि svick और डैनियल उनकी टिप्पणियों को उत्तर के रूप में बना सकता है और मैं svick's स्वीकार कर सकता हूं?
मैं ऑरलियन्स उपयोग नहीं किया है, लेकिन यह एक कस्टम कार्य अनुसूचक एफ # में यह कोडिंग पर सभी async कोड चलाने की आवश्यकता है के बाद से 'async' का समर्थन नहीं करता सिर में दर्द होने जा रहा है। सबसे अच्छा आप कर सकते हैं (AFAIK) प्रत्येक 'कार्य 'को' Async <'T> 'में' Async.AwaitTask' (yuck) जैसे कुछ के साथ परिवर्तित कर देता है। – Daniel
दरअसल, यही वह है जो मैं करने की कोशिश कर रहा था और बस एसिंक वर्कफ़्लो से बचें। हां, मुझे यकीन नहीं है कि मैं सफल हुआ हूं और किसी भी तरह से मैं कुछ सी # पैटर्न को एफ # में अनुवाद करने के तरीके पर थोड़ा सा शर्मिंदा हूं (उदाहरण के लिए मुझे 'async {}' 'का उपयोग करना चाहिए और यदि ऐसा है तो, या फिर फिर नहीं) । आम तौर पर मैं या तो भाषा में लिखता हूं और मुझे इसके बारे में वास्तव में सोचने की ज़रूरत नहीं है। – Veksi
मुझे नहीं पता कि एफ # उस भाग पर टिप्पणी करने के लिए पर्याप्त है, लेकिन सिर्फ यह कहना चाहता था कि मूल "सी (कोड) नमूना से मूल सी # कोड में कुछ बग क्या हैं। 'फ्लश' को 'शून्य 'की बजाय' async कार्य 'विधि होना आवश्यक है क्योंकि' HubConnection.Start' और 'IHupProxy.Invoke' दोनों 'कार्य' को वापस करने वाले एसिंक विधियां हैं जिनकी प्रतीक्षा की जानी चाहिए। जब आप फोरच लूप के माध्यम से जाते हैं और कार्य करते हैं तो आप शायद कार्य एकत्र करना चाहते हैं। जब फ्लश विधि के अंत में। –