2017-11-16 28 views
5

मैं एफ # में एसिंक वर्कफ़्लो को समझने की कोशिश कर रहा हूं लेकिन मुझे एक हिस्सा मिला है कि मैं वास्तव में समझ में नहीं आता हूं और उम्मीद करता हूं कि कोई मेरी मदद कर सकता है।मुझे एक Async <T> को अन्य async वर्कफ़्लो में क्यों लपेटना है और चलो! यह?

निम्नलिखित कोड ठीक काम करता है:

let asynWorkflow = async{ 
    let! result = Stream.TryOpenAsync(partition) |> Async.AwaitTask 
    return result 
    } 

let stream = Async.RunSynchronously asynWorkflow 
      |> fun openResult -> if openResult.Found then openResult.Stream else Stream(partition) 

मैं एक async कार्यप्रवाह जहां TryOpenAsync एक टास्क प्रकार रिटर्न परिभाषित करते हैं। मैं इसे Async.AwaitTask के साथ Async में रूपांतरित करता हूं। (साइड क्वेस्ट: "प्रतीक्षा करें" कार्य? यह इंतजार नहीं कर रहा है बस इसे परिवर्तित करें, है ना? मुझे लगता है कि इसका कार्य टास्क के साथ कुछ नहीं है। प्रतीक्षा करें या प्रतीक्षा करें कीवर्ड)। मैं इसे "प्रतीक्षा" करने के साथ! और इसे वापस करो। वर्कफ़्लो प्रारंभ करने के लिए मैं RunSynchronously का उपयोग करता हूं जो वर्कफ़्लो प्रारंभ करना चाहिए और परिणाम को वापस करना (इसे बांधना)। नतीजतन मैं जांचता हूं कि स्ट्रीम पाया गया है या नहीं।

लेकिन अब मेरे पहले प्रश्न पर। मुझे TryOpenAsync कॉल को अन्य async गणना में क्यों लपेटना है और चलो! ("इंतजार") यह? ईजी। निम्नलिखित कोड काम नहीं करता:

let asynWorkflow = Stream.TryOpenAsync(partition) |> Async.AwaitTask 

let stream = Async.RunSynchronously asynWorkflow 
      |> fun openResult -> if openResult.Found then openResult.Stream else Stream(partition) 

मैंने सोचा था कि AwaitTask यह बनाता है एक Async और RunSynchronously यह शुरू कर देना चाहिए। फिर परिणाम का प्रयोग करें। मुझे क्या याद आती है?

मेरा दूसरा सवाल यह है कि कोई भी "Async.Let!" क्यों है समारोह उपलब्ध है? शायद क्योंकि यह काम नहीं करता है या बेहतर नहीं है, यह निम्नलिखित कोड के साथ क्यों काम नहीं करता है?

let ``let!`` task = async{ 
    let! result = task |> Async.AwaitTask 
    return result 
    } 

let stream = Async.RunSynchronously (``let!`` (Stream.TryOpenAsync(partition)) ) 
     |> fun openResult -> if openResult.Found then openResult.Stream else Stream(partition) 

मैं बस कोशिश करता हूं TryOpenAsync पैरामीटर के रूप में लेकिन यह काम नहीं करता है। कहकर काम नहीं करता मेरा मतलब है कि पूरा एफएसआई लटका होगा। तो यह मेरे async/"प्रतीक्षा" के साथ कुछ करने के लिए है।

--- अद्यतन:

> 

Real: 00:00:00.051, CPU: 00:00:00.031, GC gen0: 0, gen1: 0, gen2: 0 
val asynWorkflow : Async<StreamOpenResult> 
val stream : Stream 

FSI में कोड काम नहीं कर के परिणाम::

> 

और तुम FSI में कुछ भी अमल नहीं कर सकते

FSI में कोड काम करने का परिणाम अब

--- अपडेट 2

मैं स्ट्रीमस्टोन का उपयोग कर रहा हूं। यहाँ सी # उदाहरण: https://github.com/yevhen/Streamstone/blob/master/Source/Example/Scenarios/S04_Write_to_stream.cs

और यहाँ Stream.TryOpenAsync: https://github.com/yevhen/Streamstone/blob/master/Source/Streamstone/Stream.Api.cs#L192

+0

आपका कोड किस तरह से काम नहीं करता है? त्रुटि क्या है? आपको 'async' वर्कफ़्लो बनाने की आवश्यकता नहीं है। – Lee

+0

जैसा कि मैंने अपने अंतिम वाक्य में उल्लेख किया है, मैं इसे एफएसआई के साथ शुरू करता हूं और यह चलता है और चलता है ("लटकता है")। एफएसआई पर कोई वापसी नहीं। मैं बस एफएसआई – KCT

उत्तर

3

की तरह यह मेरे लिए काम करना चाहिए दूसरा कोड ब्लॉक लग रहा है। अगर मैं Stream और StreamOpenResult के लिए डमी कार्यान्वयन प्रदान करता हूं तो यह इसे चलाता है।

आपको जहां भी संभव हो Async.RunSynchronously का उपयोग करना चाहिए क्योंकि यह एसिंक के उद्देश्य को हरा देता है। एक बड़ा async ब्लॉक के भीतर इस कोड को रख सकते हैं और फिर आप StreamOpenResult के लिए उपयोग होगा:

async { 
    let! openResult = Stream.TryOpenAsync(partition) |> Async.AwaitTask 
    let stream = if openResult.Found then openResult.Stream else Stream(partition) 
    return() // now do something with the stream 
    } 

आप अपने कार्यक्रम वास्तव में इसे चलाने के लिए की बहुत बाहरी छोर पर एक Async.Start या Async.RunSynchronously डाल करने के लिए आवश्यकता हो सकती है लेकिन यह बेहतर है अगर आपके पास async है (या इसे Task में परिवर्तित करें) और इसे किसी अन्य कोड (उदा।एक वेब ढांचा) जो इसे गैर-अवरुद्ध तरीके से कॉल कर सकता है।

+0

अच्छा बिंदु पुनरारंभ कर सकता हूं। कारण यह केवल बाहरी किनारे पर होना चाहिए। लेकिन इसके साथ खेलना मैंने सोचा कि दूसरा और विशेष रूप से तीसरा कोड ब्लॉक काम करना चाहिए लेकिन यह नहीं ... बस समझने की कोशिश क्यों कर रहा है। – KCT

3

नहीं कि मैं आपके प्रश्न का उत्तर किसी अन्य प्रश्न के साथ देना चाहता हूं, लेकिन: आप इस तरह कोड क्यों कर रहे हैं? यह समझने में मदद कर सकता है। क्यों नहीं बस:

let asyncWorkflow = async { 
    let! result = Stream.TryOpenAsync(partition) |> Async.AwaitTask 
    if result.Found then return openResult.Stream else return Stream(partition) } 

एक async कार्यप्रवाह बनाने केवल तुरंत उस पर RunSynchronously कॉल करने के लिए में थोड़ा बात नहीं है - यह एक Task पर .Result बुला के समान है - यह सिर्फ कार्यप्रवाह रिटर्न जब तक ब्लॉक वर्तमान धागा।

+0

संस्करण 2 में स्ट्रीमस्टोन अब टी के बजाय कार्य देता है इसलिए मुझे इसे बदलना पड़ा। एफ # में एसिंक से शुरू करना मैं इसके बारे में थोड़ा और सीखना चाहता हूं। मेरे लिए यह आपकी लिस्टिंग 36.2 जैसा दिखता है। अपनी पुस्तक में बस कार्य लौटने वाली विधि के साथ मुझे कनवर्ट करना होगा। लेकिन कुछ अलग होना चाहिए क्योंकि यह काम नहीं करता है और मैं यह पता लगाने की कोशिश करता हूं कि कार्य के साथ कार्य करने के लिए कुछ है या नहीं। – KCT

+0

दूसरा प्रश्न जो मैंने आपके कोड से बिल्कुल प्राप्त किया है, वह आपके उत्तर में फिसल गया है। मुझे परिणाम के साथ परिणाम क्यों बांधना है! परिणाम मान के लिए और परिणामस्वरूप इसका उपयोग करके अगले फ़ंक्शन में इसे पाइप नहीं कर सकता: Steam.TryOpenAsync (विभाजन) |> Async.AwaitTask |> (मजेदार परिणाम -> ...) या कम से कम ... Async.AwaitTask |> Async । "करते हैं!" |> (मजेदार परिणाम -> ...) – KCT

+1

आप आसानी से ऐसा फ़ंक्शन बना सकते हैं जो इसे करता है, जिसे शायद Async.map कहा जाता है, जो एक Async को दूसरे पर परिणाम देता है। यह तब async {} ब्लॉक को पूरी तरह से अवरुद्ध करने की आवश्यकता से बचाता है। https://gist.github.com/isaacabraham/91702cd88c5912e1a968a472de727421 इसका एक साधारण संस्करण है। –

4

मैं आपको नहीं बता सकता कि दूसरा उदाहरण यह जानने के बिना क्यों काम नहीं करता कि Stream और partition क्या हैं और वे कैसे काम करते हैं।

हालांकि, मैं यह अवसर यह इंगित करना चाहता हूं कि दो उदाहरण सख्ती से के बराबर नहीं हैं।

एफ # async क्या करना है इसके लिए "नुस्खा" की तरह है। जब आप async { ... } लिखते हैं, परिणामी गणना केवल वहां बैठी है, वास्तव में कुछ भी नहीं कर रही है। यह एक आदेश जारी करने की तरह एक समारोह घोषित करने की तरह है। केवल तभी जब आप Async.RunSynchronously या Async.Start जैसे कुछ कॉल करके इसे "प्रारंभ" करते हैं, तो यह वास्तव में चलता है। एक अनुशासनिक यह है कि आप एक ही async वर्कफ़्लो कई बार शुरू कर सकते हैं, और यह हर बार एक नया वर्कफ़्लो होने जा रहा है। IEnumerable काम करता है के समान ही।

सी # Task, दूसरी ओर, एक एसिंक गणना के लिए "संदर्भ" की तरह है जो पहले से चल रहा है। गणना जैसे ही आप Stream.TryOpenAsync(partition) पर कॉल करते हैं, गणना शुरू होती है, और वास्तव में कार्य शुरू होने से पहले Task उदाहरण प्राप्त करना असंभव है। आप await परिणामस्वरूप Task कई बार कर सकते हैं, लेकिन प्रत्येक await परिणामस्वरूप स्ट्रीम खोलने का एक नया प्रयास नहीं होगा। केवल पहले await वास्तव में कार्य के पूरा होने की प्रतीक्षा करेंगे, और प्रत्येक आगामी व्यक्ति आपको वही यादगार परिणाम देगा।

एसिंक/प्रतिक्रियाशील लिंगो में, F # async जिसे आप "ठंडा" कहते हैं, जबकि सी # Task को "गर्म" कहा जाता है।

+0

मैं स्ट्रीमस्टोन का उपयोग कर रहा हूं लेकिन इसे एफ # में करना चाहता हूं। यहां सी # उदाहरण https://github.com/yevhen/Streamstone/blob/master/Source/Example/Scenarios/S04_Write_to_stream.cs उस रेपो में आपको स्टीम भी मिल जाएगा। TryOpenAsync https://github.com/yevhen/ स्ट्रीमस्टोन/ब्लॉब/मास्टर/स्रोत/स्ट्रीमस्टोन/Stream.Api.cs # L192 उस अंतर को इंगित करने के लिए धन्यवाद। फिर मैंने कुछ नया सीखा – KCT

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