2017-04-23 12 views
10

पायथन 3 से जूलिया तक आने से तेजी से इटरेटर को उपज/उपज सिंटैक्स या उस तरह के कुछ के साथ एक समारोह के रूप में लिखने में सक्षम होना पसंद होगा।क्या जुलिएआ में जनरेटर-जैसे कार्यों से तेज़ इटरेटर बनाने के लिए कोई मैक्रो है?

जूलिया के मैक्रोज़ सुझाव देते हैं कि कोई ऐसा मैक्रो बना सकता है जो इस तरह के "जेनरेटर" फ़ंक्शन को जूलिया इटरेटर में बदल देता है। [यह भी है कि आप आसानी से इनलाइन iterators समारोह शैली है, जो एक सुविधा Iterators.jl पैकेज भी अपनी विशिष्ट iterators https://github.com/JuliaCollections/Iterators.jl#the-itr-macro-for-automatic-inlining-in-for-loops के लिए प्रदान करने की कोशिश करता है में लिखा जा सकता था लगता है]

बस मैं क्या है का एक उदाहरण देने के लिए मन में:

@asiterator function myiterator(as::Array) 
    b = 1 
    for (a1, a2) in zip(as, as[2:end]) 
    try 
     @produce a1[1] + a2[2] + b 
    catch exc 
    end 
    end 
end 

for i in myiterator([(1,2), (3,1), 3, 4, (1,1)]) 
    @show i 
end 

जहां myiterator आदर्श यथासंभव कम भूमि के ऊपर के साथ एक तेजी से इटरेटर बनाना चाहिए। और निश्चित रूप से यह केवल एक विशिष्ट उदाहरण है। मैं आदर्श रूप से कुछ ऐसा करना चाहता हूं जो सभी या लगभग सभी जनरेटर कार्यों के साथ काम करता हो।

जनरेटर फ़ंक्शन को एक पुनरावर्तक में बदलने के लिए वर्तमान में अनुशंसित तरीका कम से कम मेरे ज्ञान के लिए जूलिया के कार्य के माध्यम से है। हालांकि वे शुद्ध इटरेटर्स के रास्ते धीमा होने लगते हैं। उदाहरण के लिए यदि आप imap, chain जैसे सरल इटरेटर्स के साथ अपना फ़ंक्शन व्यक्त कर सकते हैं और इसी तरह (Iterators.jl पैकेज द्वारा प्रदान किया गया) यह बहुत बेहतर लगता है।

क्या यह जूलिया में सैद्धांतिक रूप से संभव है कि मैक्रो कनवर्टिंग जेनरेटर-स्टाइल फ़ंक्शंस को लचीला तेज़ इटरेटर में बनाया जाए?

अतिरिक्त-बिंदु-प्रश्न: यदि यह संभव है, तो क्या एक सामान्य मैक्रो हो सकता है जो ऐसे इटरेटर को रेखांकित करता है?

+0

'चैनल', जो 'टास्क की 0.6' को प्रतिस्थापित करता है, कार्य की तुलना में काफी तेज़ होना चाहिए। –

+0

मैंने अभी तक उनके बारे में नहीं सुना है, और मैंने जुलिआ के बारे में बहुत सारे दस्तावेज पढ़े हैं। सूचक के लिए धन्यवाद! – schlichtanders

+0

चैनल कार्य को प्रतिस्थापित नहीं करते --- वे एक तंत्र हैं जो कार्य संवाद करने के लिए उपयोग कर सकते हैं। –

उत्तर

2

पायथन शैली जेनरेटर - जो जूलिया में कार्यों से उपज करने के लिए निकटतम होगा - इसमें अंतर्निहित ओवरहेड की उचित मात्रा शामिल है। आपको कार्यों को स्विच करना होगा, जो गैर-तुच्छ है और सीधे एक कंपाइलर द्वारा समाप्त नहीं किया जा सकता है। यही कारण है कि जूलिया के इटरेटर उन कार्यों पर आधारित हैं जो एक आम तौर पर अपरिवर्तनीय, सरल राज्य मूल्य और दूसरे को बदलते हैं। लंबी कहानी छोटी: नहीं, मुझे विश्वास नहीं है कि यह परिवर्तन स्वचालित रूप से किया जा सकता है।

2

इस फार्म से कुछ iterators इस तरह लिखा जा सकता है:

myiterator(as) = (a1[1] + a2[2] + 1 for (a1, a2) in zip(as, as[2:end])) 

इस कोड (संभावित) inlined जा सकता है।

इसे पूरी तरह से सामान्य करने के लिए, यह एक मैक्रो लिखना संभव है जो निरंतर-गुजरने वाली शैली (सीपीएस) के लिए अपने तर्क को परिवर्तित करता है, जिससे इसे निलंबित करने और निष्पादन को पुनरारंभ करना संभव हो जाता है, जिससे इटरेटर की तरह कुछ मिलता है। सीमित निरंतरता इस (https://en.wikipedia.org/wiki/Delimited_continuation) के लिए विशेष रूप से उपयुक्त है। परिणाम अज्ञात कार्यों का एक बड़ा घोंसला है, जो कार्य स्विचिंग से तेज़ हो सकता है, लेकिन जरूरी नहीं है, क्योंकि दिन के अंत में इसे एक ही मात्रा में राज्य को ढेर करने की आवश्यकता होती है।

मैं इस तरह के एक परिवर्तन यहाँ का एक उदाहरण है के लिए हो (femtolisp में हालांकि, नहीं जूलिया): https://github.com/JeffBezanson/femtolisp/blob/master/examples/cps.lsp यह एक define-generator मैक्रो करता है कि आप क्या वर्णन के साथ समाप्त होता है। लेकिन मुझे यकीन नहीं है कि यह जूलिया के लिए ऐसा करने के प्रयास के लायक है।

1

बहुत अधिक प्रदर्शन खोने के बिना पाइथन जनरेटर को जूलिया में अनुवाद करने के तरीके के बारे में सोचने के बाद, मैंने उच्च स्तरीय कार्यों की एक लाइब्रेरी को कार्यान्वित और परीक्षण किया जो एक निरंतर शैली में पायथन-जैसे/कार्य-जैसे जेनरेटर लागू करता है। https://github.com/schlichtanders/Continuables.jl

अनिवार्य रूप से, विचार संबंध है पायथन के yield/जूलिया के produce एक समारोह है जो हम एक अतिरिक्त पैरामीटर के रूप में बाहर से ले के रूप में। मैंने इसे जारी रखने के लिए cont कहा। एक सीमा के इस reimplementation पर उदाहरण के लिए देखो

crange(n::Integer) = cont -> begin 
    for i in 1:n 
    cont(i) 
    end 
end 

आप बस निम्नलिखित कोड द्वारा सभी पूर्णांकों योग

function sum_continuable(continuable) 
    a = Ref(0) 
    continuable() do i 
    a.x += i 
    end 
    a.x 
end 

# which simplifies with the macro [email protected] to 
@Ref function sum_continuable(continuable) 
    a = Ref(0) 
    continuable() do i 
    a += i 
    end 
    a 
end 

sum_continuable(crange(4)) # 10 

आप उम्मीद है कि इस बात से सहमत रूप में, आप लगभग तरह आप काम किया है | continuables साथ काम कर सकते कर सकते हैं पाइथन में जनरेटर या जुलिआ में कार्य के साथ। for लूप के बजाय नोटेशन का उपयोग करना एक ऐसी चीज है जिसका उपयोग आप करना चाहते हैं।

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

प्रदर्शन कुछ मामलों में अविश्वसनीय रूप से तेज है और कुछ मामलों में इटरेटर से भी तेज़ है (विशेष रूप से Continuables.cmap का निष्पक्ष कार्यान्वयन Iterators.imap से तीव्रता के आदेश है)। अधिक जानकारी के लिए github repository https://github.com/schlichtanders/Continuables.jl के Readme.md देखें।


संपादित करें: अधिक सीधे अपने ही सवाल का जवाब करने के लिए, एक मैक्रो @asiterator के लिए कोई जरूरत नहीं है, बस सीधे निरंतरता शैली का उपयोग करें।

mycontinuable(as::Array) = cont -> begin 
    b = 1 
    for (a1, a2) in zip(as, as[2:end]) 
    try 
     cont(a1[1] + a2[2] + b) 
    catch exc 
    end 
    end 
end 

mycontinuable([(1,2), (3,1), 3, 4, (1,1)]) do i 
    @show i 
end 
संबंधित मुद्दे