2015-04-26 8 views
7

मैं पहली बार के लिए Clojure core.async पर देख रहा हूँ, और रिच हिक्की द्वारा इस उत्कृष्ट प्रस्तुति के माध्यम से जा रहा था:clojure core.async चैनल कैसे साफ़ हो जाते हैं?

: http://www.infoq.com/presentations/clojure-core-async

मैं उदाहरण के बारे में एक प्रश्न वह अपने प्रस्तुति के अंत में पता चलता था

core.async Web Example

रिच के अनुसार, यह उदाहरण मूल रूप से एक विशिष्ट क्वेरी के लिए वेब, वीडियो और छवि परिणाम प्राप्त करने का प्रयास करता है। यह उन परिणामों में से प्रत्येक के लिए समानांतर में दो अलग-अलग स्रोतों की कोशिश करता है, और केवल प्रत्येक के लिए सबसे तेज़ परिणाम निकालता है। और पूरा ऑपरेशन 80ms से अधिक नहीं ले सकता है, इसलिए यदि हम उदाहरण नहीं प्राप्त कर सकते हैं 80ms में एक छवि परिणाम, हम बस छोड़ देंगे। 'सबसे तेज़' फ़ंक्शन एक नया चैनल बनाता है और देता है, और परिणाम प्राप्त करने और इसे चैनल पर रखने के लिए दो प्रक्रियाओं को रेसिंग शुरू करता है। फिर हम 'सबसे तेज़' चैनल का पहला परिणाम लें और इसे सी चैनल पर थप्पड़ मार दें।

मेरा प्रश्न: हमारे पहले परिणाम लेने के बाद इन तीन अस्थायी, अज्ञात 'सबसे तेज़' चैनलों का क्या होता है? संभवतः अभी भी एक प्रक्रिया है जो दूसरे परिणाम को चैनल पर रखने की कोशिश कर रही है, लेकिन कोई भी सुन रहा है, इसलिए यह वास्तव में कभी पूरा नहीं होता है। और चूंकि चैनल कभी भी किसी भी चीज़ से बंधे नहीं है, ऐसा प्रतीत नहीं होता है कि हमारे पास इसके साथ कुछ भी करने का कोई तरीका नहीं है। क्या प्रक्रिया & चैनल "एहसास" होगी कि कोई भी अपने परिणामों की परवाह नहीं करेगा और खुद को साफ करेगा? या क्या हम अनिवार्य रूप से इस कोड में तीन चैनल/प्रक्रियाओं को "रिसाव" करते थे?

उत्तर

3

कोई रिसाव नहीं है।

पार्क किए गए go एस उन चैनलों से जुड़े हुए हैं जिन पर उन्होंने एक ऑपरेशन करने का प्रयास किया था और इसके अलावा कोई स्वतंत्र अस्तित्व नहीं था। यदि अन्य कोड चैनलों में रुचि खो देता है तो एक निश्चित go पर पार्क किया जाता है (एनबी। go कई चैनलों पर एक पटर/लेने वाला बन सकता है यदि यह alt!/alts! पर पार्क करता है), तो आखिरकार यह उन लोगों के साथ जीसीड होगा चैनल।

एकमात्र चेतावनी यह है कि जीसीएड होने के लिए, go को वास्तव में पहले पार्क करना होगा।इसलिए किसी भी go कि कभी पार्किंग (<!/>!/alt!/alts!) के बिना एक पाश में कोई काम कर रखता है वास्तव में हमेशा के लिए जीना होगा। हालांकि, इस प्रकार के कोड को दुर्घटना से लिखना मुश्किल है।

+0

हम्म, ठीक है। अब आपके पास और लियोन से दो विवादित उत्तर हैं। क्या आप अपने दावे का संदर्भ प्रदान कर पाएंगे? – Ord

+0

हां, कृपया कार्यान्वयन विवरण से लिंक करें। साथ ही, कृपया बताएं कि यह उपरोक्त कोड नमूने में कैसे काम करेगा। –

+0

ई जी। एल 4 में गो ब्लॉक ले लो: मान लीजिए 'सी' डाल को अवरुद्ध कर रहा है। 'सबसे तेज़' एक दूसरा पॉट बनाता है जिसे उपभोग नहीं किया जाता है। जब वास्तव में, उपरोक्त कोड नमूने में, 'सी' हैं और चैनल 'सबसे तेज़' कचरा द्वारा वापस लौटाया गया है? –

1

माना जाता है कि fastest द्वारा उत्पादित एक चैनल केवल सबसे तेज़ क्वेरी विधि का परिणाम देता है और फिर बंद हो जाता है।

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

ध्यान दें कि यह भी हो सकता है यदि चैनल talt! खंड में चुना गया है।

इसे ठीक करने का सामान्य तरीका चैनल को close! के साथ पिछले go ब्लॉक में बंद करना होगा। तब बंद चैनल में किए गए पॉट को तब गिरा दिया जाएगा और निर्माता समाप्त हो सकते हैं।

समस्या fastest के कार्यान्वयन में भी हल की जा सकती है। fastest में बनाई गई प्रक्रिया स्वयं alts! और timeout के माध्यम से डाल सकती है और समाप्त हो सकती है कि उत्पादित मूल्यों को निश्चित समय के भीतर नहीं लिया जाता है।

मुझे लगता है कि रिच ने स्लाइड में समस्या को कम लंबे उदाहरण के पक्ष में संबोधित नहीं किया था।

+0

हम्म ठीक है। अब आपके पास और मीकल से दो विवादित उत्तर हैं। क्या आप अपने दावे का संदर्भ प्रदान कर पाएंगे? – Ord

+0

यह हो सकता है कि जाने वाले ब्लॉक के बारे में माइकल का बयान सही है। हां हम नहीं जानते कि 'सबसे तेज़' उपयोगों का कार्यान्वयन ब्लॉक हो जाता है या नहीं। यह सूत्र है, जो समवर्ती खोज प्रश्नों के मामले में होने की संभावना है spawns, और के माध्यम से डालता अवरुद्ध करता है '> !!' इन परित्यक्त धागे हमेशा के लिए थ्रेड पूल में रहने के लिए जा रहे हैं जब तक JVM पर्याप्त अनुरोध के बाद मर जाता है। –

+0

ऐसा नहीं है कि प्रस्तुति कि सिर्फ कॉल (जाना ... (नींद ...) किया जाता है) के लिए उदाहरण के कोड में एक डमी कार्यान्वयन है, इसलिए इसमें इस प्रयोग के सवाल का जवाब देने में एक संदर्भ के रूप कोई फायदा नहीं है। –

3

चेतावनियां और एक तरफ अपवाद हैं, आप आरईपीएल पर JVM पर कचरा संग्रहण परीक्षण कर सकते हैं।

जैसे:

(require '[clojure.core.async :as async]) 
=> nil 

(def c (async/chan)) 
=> #'user/c 
(def d (async/go-loop [] 
     (when-let [v (async/<! c)] 
      (println v) 
      (recur)))) 
=> #'user/d 

(async/>!! c :hi) 
=> true 
:hi  ; core.async go block is working 

(import java.lang.ref.WeakReference) 
=> java.lang.ref.WeakReference ; hold a reference without preventing garbage collection 
(def e (WeakReference. c)) 
=> #'user/e 
(def f (WeakReference. d)) 
=> #'user/f 

(.get e) 
=> #object[...] 
(.get f) 
=> #object[...] 

(def c nil) 
=> #'user/c 
(def d nil) 
=> #'user/d 
(println "We need to clear *1, *2 and *3 in the REPL.") 
We need to clear *1, *2 and *3 in the REPL. 
=> nil 
(println *1 *2 *3) 
nil #'user/d #'user/c 
=> nil 
(System/gc) 
=> nil 
(.get e) 
=> nil 
(.get f) 
=> nil 

क्या सिर्फ हुआ? मैंने एक गो ब्लॉक सेट किया और चेक किया कि यह काम कर रहा था। तब संचार चैनल (ग) और यात्रा के दौरान ब्लॉक वापसी चैनल (घ) का पालन करने के लिए एक WeakReference इस्तेमाल किया। तब मैं (सहित *1, *2 और *3 मेरी आरईपीएल द्वारा बनाई गई) ग और घ के सभी संदर्भ (System.gc Javadoc और भाग्यशाली, मजबूत गारंटी नहीं है) को हटा दिया, कचरा संग्रहण का अनुरोध किया है, और फिर कहा कि मेरी कमजोर संदर्भ को मंजूरी दे दी गई थी।

इस मामले में कम से कम, शामिल निकाल दिया गया था चैनलों के लिए संदर्भ एक बार, चैनल, थे कचरा एकत्र (मेरी असफलता उन्हें बंद करने के लिए की परवाह किए बिना!)

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