2017-05-04 13 views
6

क्या यह सुरक्षित है, वादे के बीच एक सरणी साझा करने के लिए जैसा कि मैंने निम्नलिखित कोड में किया था?क्या यह सुरक्षित है, धागे के बीच एक सरणी साझा करने के लिए?

#!/usr/bin/env perl6 
use v6; 

sub my_sub ($string, $len) { 
    my ($s, $l); 
    if $string.chars > $len { 
     $s = $string.substr(0, $len); 
     $l = $len; 
    } 
    else { 
     $s = $string; 
     $l = $s.chars; 
    } 
    return $s, $l; 
} 

my @orig = <length substring character subroutine control elements now promise>; 
my $len = 7; 
my @copy; 
my @length; 
my $cores = 4; 
my $p = @orig.elems div $cores; 
my @vb = (0..^$cores).map: { [ $p * $_, $p * ($_ + 1) ] }; 
@vb[@vb.end][1] = @orig.elems; 

my @promise; 
for @vb -> $r { 
    @promise.push: start { 
     for $r[0]..^$r[1] -> $i { 
      (@copy[$i], @length[$i]) = my_sub(@orig[$i], $len); 
     } 
    }; 
} 
await @promise; 
+0

वादे का पूरा बिंदु यह है कि कुछ वापस करने का वादा, आप जानबूझकर 'स्टार्ट' स्टेटमेंट उपसर्ग से कुछ भी उपयोगी नहीं कर रहे हैं। –

+0

लेकिन 'स्टार्ट' अधिक करता है तो केवल कुछ लौटाता है। मुझे समानांतर में कोड चलाने के लिए समवर्ती भाग में रूचि है ताकि मेरे सीपीयू के सभी कोरों को काम करना पड़े। –

+1

मैं जो कह रहा हूं वह एक रिंच लेने के लिए है, और फिर इसे नाखून में पाउंड करने के लिए उपयोग करना है। कौन सा काम करता है, ... मुझे लगता है। –

उत्तर

14

यह निर्भर करता है कि आप "सरणी" और "साझा करें" को कैसे परिभाषित करते हैं।अब तक सरणी चला जाता है के रूप में, वहाँ दो मामलों में अलग से विचार करने की आवश्यकता है कि कर रहे हैं:

  • फिक्स्ड आकार सरणियों (घोषित my @a[$size]); इसमें निश्चित आयामों के साथ बहु-आयामी सरणी शामिल हैं (जैसे my @a[$xs, $ys])। इनकी दिलचस्प संपत्ति है कि उन्हें समर्थन देने वाली स्मृति का आकार कभी नहीं बदला जाना चाहिए।
  • गतिशील सरणी (घोषित my @a), जो मांग पर बढ़ती है। ये, हुड के नीचे, वास्तव में समय के साथ स्मृति के कई हिस्सों का उपयोग करते हुए बढ़ते हैं।

अब तक साझा करने के रूप में चला जाता है, वहाँ भी तीन मामलों हैं:

  • मामले में जहां एक से अधिक थ्रेड अपने जीवनकाल में सरणी स्पर्श करते हैं, लेकिन केवल एक कभी एक समय में यह छू जा सकता है, की वजह से कुछ समवर्ती नियंत्रण तंत्र या समग्र कार्यक्रम संरचना। इस मामले में सरणी को "सरणी का उपयोग कर समवर्ती संचालन" के अर्थ में कभी साझा नहीं किया जाता है, इसलिए डेटा रेस रखने की कोई संभावना नहीं है।
  • केवल पढ़ने योग्य, गैर आलसी मामला। यह वह जगह है जहां कई समवर्ती संचालन एक गैर-आलसी सरणी तक पहुंचते हैं, लेकिन केवल इसे पढ़ने के लिए।
  • पढ़ना/लिखना मामला (जब पढ़ता है वास्तव में एक लिखने का कारण बनता है क्योंकि सरणी को आलसी मूल्यांकन की मांग करने वाले कुछ सौंपा गया है; ध्यान दें कि यह निश्चित आकार के सरणी के लिए कभी नहीं हो सकता है, क्योंकि वे कभी आलसी नहीं होते हैं)। इस प्रकार

तब हम सुरक्षा को संक्षेप में प्रस्तुत कर सकते हैं:

     | Fixed size  | Variable size | 
---------------------+----------------+---------------+ 
Read-only, non-lazy | Safe   | Safe   | 
Read/write or lazy | Safe *   | Not safe  | 

* चेतावनी का संकेत है, जबकि यह देखने के पर्ल 6 के दृष्टिकोण से सुरक्षित हो, आपको निश्चित रूप से सुनिश्चित करें कि आप नहीं कर रहे हैं बनाने के लिए है एक ही सूचकांक के साथ विरोधाभासी चीजें।

तो संक्षेप में, निश्चित आकार सरणी आप सुरक्षित रूप से साझा कर सकते हैं और अलग-अलग थ्रेडों के तत्वों को असाइन कर सकते हैं "कोई समस्या नहीं है" (लेकिन झूठी साझाकरण से सावधान रहें, जो आपको ऐसा करने के लिए भारी प्रदर्शन दंड का भुगतान कर सकता है)। गतिशील सरणी के लिए, यह केवल सुरक्षित है अगर उन्हें केवल उस अवधि के दौरान ही पढ़ा जाएगा जब वे साझा किए जा रहे हैं, और फिर भी यदि वे आलसी नहीं हैं (हालांकि दिया गया सरणी असाइनमेंट अधिक उत्सुक है, तो आप उस स्थिति को हिट करने की संभावना नहीं रखते हैं गलती से)। लेखन, यहां तक ​​कि विभिन्न तत्वों के लिए, बढ़ते संचालन के कारण डेटा हानि, क्रैश या अन्य बुरे व्यवहार का जोखिम है।

तो, मूल उदाहरण पर विचार करते हुए, हम my @copy; और my @length; गतिशील सरणी देखते हैं, इसलिए हमें समवर्ती परिचालनों में उन्हें नहीं लिखना चाहिए। हालांकि, ऐसा होता है, इसलिए कोड को सुरक्षित नहीं किया जा सकता है।

अन्य पद पहले से ही बेहतर दिशाओं में इशारा करते हुए एक सभ्य नौकरी करते हैं, लेकिन किसी ने भी गोरी के विवरणों को नकार दिया।

5

बस कोड कि start बयान उपसर्ग के साथ चिह्नित है मान ताकि पर्ल 6 आप के लिए तुल्यकालन को प्रबंधित कर सके। उस सुविधा का पूरा बिंदु कौन सा है।
फिर आप सभी वादे के लिए इंतजार कर सकते हैं, और await कथन का उपयोग करके सभी परिणामों को प्राप्त कर सकते हैं।

my @promise = do for @vb -> $r { 

    start 

     do # to have the 「for」 block return its values 

     for $r[0]..^$r[1] -> $i { 
      $i, my_sub(@orig[$i], $len) 
     } 
} 

my @results = await @promise; 

for @results -> ($i,$copy,$len) { 
    @copy[$i] = $copy; 
    @length[$i] = $len; 
} 

start बयान उपसर्ग केवल ऊपरी तौर पर समानांतरवाद से संबंधित तरह-की है।
जब आप इसका इस्तेमाल करते हैं तो आप कह रहे हैं, "मुझे अभी इन परिणामों की आवश्यकता नहीं है, लेकिन शायद बाद में"।

कारण यह रिटर्न एक Promise (asynchrony), और नहीं एक Thread (संगामिति)

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

तो कार्यान्वयन वास्तव में है कि, यह एक गतिरोध की तरह कुछ में परिणाम सकता है अगर आप के बजाय लगातार यह .status विधि यह Planned से Kept या Broken को बदलने के लिए इंतजार कर रहा है फोन करके Promise पोल, और उसके बाद ही उसके परिणाम के लिए पूछने के लिए किया था ।
यह कारण है कि डिफ़ॉल्ट शेड्यूलर किसी भी Promise कोड पर काम करना शुरू कर देगा यदि उसके पास कोई अतिरिक्त थ्रेड है।


मैं jnthn की बात “Parallelism, Concurrency, and Asynchrony in Perl 6” देखने की सलाह देता हूं।
slides

+0

मूल्यों को लौटाना ('await' के उपयोग के लिए) और फिर मानों को सही जगह पर कॉपी करने से यह थोड़ा धीमा हो गया। इसके अलावा कोड मेरे लिए पढ़ना अधिक कठिन है। मैंने 'थ्रेड' इंटरफेस का उपयोग करने की कोशिश की; मुझे कोई गति लाभ नहीं मिला और यह अधिक निम्न स्तर है। –

+0

@sid_com इसे सरणी में डालने से यह लूप प्रक्रियाओं से पहले प्रतीक्षा कर सकता है। यदि आप 'लूप' में 'प्रतीक्षा' रखते हैं, जहां '@ परिणाम' है, तो इसे पूरा करने से पहले मूल्यों को संसाधित करना प्रारंभ करना चाहिए। –

4

इस उत्तर MoarVM पर स्थिति की मेरी समझ पर लागू होता है, यकीन नहीं क्या कला के राज्य JVM बैकएंड (या जावास्क्रिप्ट बैकएंड fwiw) पर है।

  • कई धागे से स्केलर को सुरक्षित रूप से किया जा सकता है।
  • कई धागे से एक अदिश संशोधन करना एक segfault के लिए डर के बिना किया जा सकता है, लेकिन आप अद्यतन छूट सकते हैं:

$ perl6 -e 'my $i = 0; await do for ^10 { start { $i++ for ^10000 } }; say $i' 46785

ही सरणियों की तरह करने के लिए और अधिक जटिल डेटा संरचनाओं लागू होता है (उदाहरण के लिए लापता मूल्यों को धक्का दिया जा रहा है) और हैश (गायब कुंजी जोड़े जा रहे हैं)।

इसलिए, यदि आपको अपडेट याद नहीं आते हैं, तो कई धागे से साझा डेटा संरचनाओं को बदलना चाहिए। यदि आपको दिमागी याद आती है, जो मुझे लगता है कि आप आम तौर पर चाहते हैं, तो आपको अपने एल्गोरिदम को एक अलग तरीके से स्थापित करना चाहिए, जैसा कि @Zoffix Znet और @raiph द्वारा सुझाया गया है।

-1

सं





गंभीरता से। अन्य उत्तर कार्यान्वयन के बारे में बहुत अधिक धारणाएं प्रतीत होते हैं, जिनमें से कोई भी spec द्वारा परीक्षण नहीं किया जाता है।

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