लाइनक टू टास्क एंड कंटिन्यूएशन मोनाड

अपने async और प्रतीक्षा के साथ C # 5.0 की घोषणा के बाद, मुझे एसिंक्रोनस प्रोग्रामिंग में थोड़ी रुचि मिली, इस दिशा में खुदाई हुई जिसमें इस पाठ की उत्पत्ति हुई।

लेख पढ़ने की प्रक्रिया में आप सीखेंगे / धोएँ।





इकाई



मठ में अनिवार्य रूप से तीन भाग होते हैं।



आमतौर पर इन दो कार्यों को रिटर्न और बाइंड कहा जाता है, लेकिन शार्प में हम उन्हें [मोनाड नाम] और सिलेक्टनी कहेंगे।



शायद मोनद


मुल्ला शायद, नुल्लेबल के जुड़वाँ भाई मानें। एक कंटेनर जिसमें या तो एक मूल्य हो सकता है या जिसमें कुछ भी नहीं है।

public class Maybe<T> { public static readonly Maybe<T> Nothing = new Maybe<T>(); public T Value { get; private set; } public bool HasValue { get; private set; } private Maybe() { HasValue = false; } public Maybe(T value) { Value = value; HasValue = true; } public override string ToString() { if(HasValue) return Value.ToString(); return "Nothing"; } }
      
      





इस सन्यासी के उपयोगी गुणों में से एक, अगर अभिव्यक्ति में कहीं भी कुछ नहीं मिला है, तो पूरी अभिव्यक्ति कुछ नहीं होगी।

यहां हमारी दो विशेषताएं हैं।

 public static class MaybeEx { public static Maybe<T> ToMaybe<T>(this T value) { return new Maybe<T>(value); } public static Maybe<U> SelectMany<T, U>(this Maybe<T> m, Func<T, Maybe<U>> k) { if (m.HasValue) return k(m.Value); return Maybe<U>.Nothing; } }
      
      





ToMaybe के साथ सब कुछ स्पष्ट है, SelectMany के साथ ऐसा लगता है कि, हम कंटेनर m लेते हैं, और फ़ंक्शन k को इसकी सामग्री पर लागू करते हैं यदि कोई मूल्य है।

मान लीजिए हम दो नंबर जोड़ना चाहते हैं

 var a = 1.ToMaybe(); var b = Maybe<int>.Nothing; Func<int, Maybe<int>> k = x => b.SelectMany(y => (y + x).ToMaybe()); var result = a.SelectMany(k); //result == Nothing,   b = 2.ToMaybe()  3
      
      





हम देखते हैं कि तह करने से पहले हमें कंटेनर से दो बार मानों को खींचने के लिए SelectMany का उपयोग करना था। हेपिंग फ़ंक्शन से छुटकारा पाने के लिए, कुछ भाषाओं में चीनी है, हास्केल में संकेतन, एफ # गणना अभिव्यक्ति, ठीक है, हम याद रख सकते हैं कि अभिव्यक्ति

 from x in a from y in b select x + y;
      
      





यह है

 a.SelectMany(x => b, (x, y) => x + y);
      
      





यानी फॉर्म का एक अतिरिक्त SelectMany लागू करके

 public static Maybe<V> SelectMany<T, U, V>( this Maybe<T> m, Func<T, Maybe<U>> k, Func<T, U, V> s) { return m.SelectMany(x => k(x).SelectMany(y => s(x, y).ToMaybe())); }
      
      





जिसमें बस बहुत डबल कंटेनर विस्तार शामिल है, शायद फॉर्म में संचालन के साथ रिकॉर्ड कर सकता है।

 var result = from x in 1.ToMaybe() from y in 2.ToMaybe() select x + y;
      
      







CPS (कंटीन्यू-पासिंग स्टाइल)





सीपीएस अनिवार्य रूप से कॉलबैक के साथ काम करता है, अर्थात सामान्य गणना क्रम का उपयोग करने के बजाय

 var x = GetPage("http://habrahabr.ru"); var y = Translate(x); Display(y);// Display  Console.WriteLine
      
      





प्रत्येक फ़ंक्शन का एक अतिरिक्त पैरामीटर होता है, जिसमें हम गणना जारी रखने के लिए फ़ंक्शन पास करते हैं।

 GetPage("http://habrahabr.ru", x => Translate(x, y => Display(y)));
      
      





इसका उपयोग अक्सर किया जाता है यदि कोई फ़ंक्शन कहीं अतुल्यकालिक अनुरोध करता है और हम नहीं चाहते हैं कि धागा निष्क्रिय या फ्रीज गुई हो।

मोनाड और सीपीएस को मिलाकर हम प्राप्त करते हैं

सीक्वल मोनाड


मोनाड का अधिक या कम मानक संस्करण एक फ़ंक्शन है जो इनपुट के रूप में एक और फ़ंक्शन लेता है, हम आउटपुट को शून्य होने पर साधारण मामले में खुद को प्रतिबंधित करते हैं। फिर ऐसे प्रतिनिधि के रूप में मोनाद का प्रतिनिधित्व किया जा सकता है।

 public delegate void Cont<T>(Action<T> k);
      
      





फ़ंक्शन k (जारी) को इनपुट फ़ंक्शन को आपूर्ति की जाती है, जिसमें T. जैसी कोई चीज़ पहले से ही स्थानांतरित हो जाती है। यहां हमारे परिचित तीन फ़ंक्शन हैं।

 public static class ContEx { public static Cont<T> ToCont<T>(this T value) { return k => k(value); } public static Cont<T1> SelectMany<T, T1>(this Cont<T> c, Func<T, Cont<T1>> f) { return k => c(r => f(r )(k)); } public static Cont<T2> SelectMany<T, T1, T2>(this Cont<T> c, Func<T, Cont<T1>> f, Func<T, T1, T2> s) { return c.SelectMany(x => f(x).SelectMany(y => s(x, y).ToCont())); } }
      
      





ToCont - जारी रखने के लिए k बस मान पास करें। SelectMany - हम monad से r लेते हैं, इसे फंक्शन f में पास करते हैं और एक कॉमन कंटिन्यूशन k के साथ एक नया मोनड कहते हैं।



कार्य


यह याद रखने का समय है कि टास्क क्या है। यह एक कंटेनर है जिसमें अपने आप में एक कार्रवाई होती है, जिसका परिणाम धारा को अवरुद्ध करके परिणाम संपत्ति का उपयोग करके प्राप्त किया जा सकता है, और सीपीएस में मैं कंटिन्यूविथ विधि का उपयोग करता हूं।

एक कार्य बनाएँ।

 var task = Task<int>.Factory.StartNew(() => 10); //  10
      
      





हमें इसका फल मिलता है

 task.ContinueWith(task => Display(task.Result));
      
      





एक बार टास्क में सीपीएस होने के बाद, आप एक दूसरे को बदलने की कोशिश कर सकते हैं।

 public static Cont<T> ToCont<T>(this Task<T> task) { return k => task.ContinueWith(task => k(task.Result)); }
      
      







कार्य उदाहरण



मान लीजिए कि हमारे पास तीन अतुल्यकालिक सेवाएं हैं। Url द्वारा पुरानी महिला की सामग्री प्राप्त करें, पाठ का अनुवाद करें और एक पाठ विश्लेषण करें, जिसके परिणामस्वरूप एक संख्या होगी।

 public static Task<string> GetPage(string url) { return Task<string>.Factory.StartNew(() => { Console.WriteLine("get page start " + url); Thread.Sleep(3000); Console.WriteLine("get page complete"); return "page content"; }); } public static Task<string> Translate(string text) { return Task<string>.Factory.StartNew(() => { Console.WriteLine("translate start"); Thread.Sleep(3000); Console.WriteLine("translate complete"); return "text translation"; }); } public static Task<int> Analyse(string text) { return Task<int>.Factory.StartNew(() => { Console.WriteLine("analyse start"); Thread.Sleep(3000); Console.WriteLine("analyse complete"); return 100; }); }
      
      







कल्पना करें कि सीपीएस में इन तीन कार्यों के माध्यम से मार्ग कैसा दिखेगा, हम भयभीत होंगे और तुरंत लिंक का उपयोग करेंगे, कार्यों को मठों में परिवर्तित करेंगे।

 var result = from x in GetPage("www.example.com").ToCont() from y in Translate(x).ToCont() from z in Analyse(y).ToCont() select z; result(Display);
      
      





यदि हमें url द्वारा अनुवादित पृष्ठ प्राप्त करने के लिए कहीं और की आवश्यकता है, तो इसे एक अलग विधि में निकाला जा सकता है

 private static Cont<string> GetPageTranslation(string url) { return from x in GetPage(url).ToCont() from y in Translate(x).ToCont() select y; } var result = from x in GetPageTranslation("http://habrahabr.ru") from a in Analyse(x).ToCont() select a; result(Display);
      
      





चूंकि ToCont का उपयोग हर जगह किया जाता है, इसलिए अतिरिक्त इकाई से छुटकारा पाने की कोशिश न करें।

 public static Task<T1> SelectMany<T, T1>(this Task<T> c, Func<T, Task<T1>> f) { return c.ContinueWith(task => f(task.Result)).Unwrap(); } public static Task<T2> SelectMany<T, T1, T2>(this Task<T> c, Func<T, Task<T1>> f, Func<T, T1, T2> s) { return c.ContinueWith(t => f(t.Result).ContinueWith(x => s(t.Result, x.Result))).Unwrap(); }
      
      





प्रकार का विस्तार करने के लिए अनवैप की आवश्यकता होती है
 Task<Task<T>>
      
      



जो दो कार्यों को मिलाकर प्राप्त किया जाता है।

अब सभी ToCont को हटाकर आप एक ही परिणाम प्राप्त कर सकते हैं।

 private static Task<string> GetTranslation(string url) { return from x in GetPage(url) from y in Translate(x) select y; }
      
      





कुल मिलाकर, हम यह मान सकते हैं कि टास्क अनिवार्य रूप से निरंतरता है।

ठीक है, उदाहरण के लिए, हम एक फ़ंक्शन लिखते हैं जो यूआरएल की सूची के लिए लौटता है, विश्लेषण मूल्यों की सूची। इस बारे में सोचें कि यह सीपीएस में कैसे दिखेगा।

 private static Task<IEnumerable<int>> Analyse(IEnumerable<string> list) { var result = from url in list select from x in GetTranslation(url) from a in Analyse(x) select a; return Task.Factory.ContinueWhenAll(result.ToArray(), x => x.Select(y => y.Result)); }
      
      





ContinueWhenAll - हम प्रतीक्षा करते हैं जब सभी परिणाम प्राप्त करने के लिए सभी कार्यों को पूरा किया जाता है।



 var urls = new[] {"url1", "url2", "url3"}; var r = Analyse(urls); r.ContinueWith(x => Console.WriteLine(x.Result.Sum()));
      
      







निष्कर्ष



यह संभावना नहीं है कि यह सब कम से कम कुछ व्यावहारिक अर्थ है, इसलिए इस पाठ को असामान्य प्रोग्रामिंग की श्रेणी से विचार के लिए जानकारी माना जा सकता है। इसके अलावा, हर कोई IObservable और IObserver इंटरफेस और IObserver.OnNext (T मान) इंटरफ़ेस के बारे में सोच सकता है



PS अच्छे के लिए, यह इंतजार करने के साथ उन समानों पर स्पर्श करने के लिए चोट नहीं करेगा, लेकिन मुझे ctp स्थापित करने की इच्छा नहीं है, इसलिए मेरे पास उनके बारे में काफी सतही विचार हैं, लेकिन मुझे लगता है कि बिंदु ऊपर से बहुत अलग नहीं है, यही काम चल रहा है कार्यों के साथ, लेकिन लिंक के बजाय, संकलक का उपयोग करके गणना प्रवाह के रूपांतरण का उपयोग किया जाता है।



All Articles