2012-10-05 20 views
7

यह प्रश्न जिज्ञासा का एक बिंदु है, क्योंकि नीचे दिए गए दो कार्यक्रमों में से एक है।पर्ल थ्रेड्स में कचरा संग्रह

मैं छवियों का उपयोग कर रहा हूं :: मैजिक कई फ़ोटो का आकार बदलने के लिए। थोड़ी देर बचाने के लिए, मैं प्रत्येक तस्वीर पर अपने स्वयं के धागे में काम करता हूं, और एक साथ काम करने वाले धागे की संख्या को सीमित करने के लिए एक सेमफोर का उपयोग करता हूं। मूल रूप से मैंने प्रत्येक थ्रेड को एक बार में चलाने की इजाजत दी, लेकिन स्क्रिप्ट सभी फ़ोटो के लिए 3.5 जीबी आवंटित करेगी (मेरे पास केवल 2 जीबी उपलब्ध है), और डिस्क पर सभी स्वैपिंग के कारण स्क्रिप्ट सामान्य से 5x धीमी गति से चलती है।

काम, सेमाफोर संस्करण कोड इस तरह दिखता है:

use threads; 
use Thread::Semaphore; 
use Image::Magick; 

my $s = Thread::Semaphore->new(4); 
foreach (@photos) { 
    threads->create(\&launch_thread, $s); 
} 
foreach my $thr (reverse threads->list()) { 
    $thr->join(); 
} 

sub launch_thread { 
    my $s = shift; 
    $s->down(); 
    my $image = Image::Magick->new(); 

    # do memory-heavy work here 

    $s->up(); 
} 

यह जल्दी से 500MB आबंटित करता है, और कभी अधिक की आवश्यकता के बिना काफी अच्छी तरह से चलाता है। (धागे एक बिंदु बनाने के लिए उलटे क्रम में शामिल हो गए हैं।)

मैंने सोचा अगर वहाँ एक साथ 80 धागे शुरू करने और उनमें से ज्यादातर को अवरुद्ध करने से भूमि के ऊपर हो सकता है, तो मैं मुख्य थ्रेड ब्लॉक करने के लिए मेरी स्क्रिप्ट बदल:

my $s = Thread::Semaphore->new(4); 
foreach (@photos) { 
    $s->down(); 
    threads->create(\&launch_thread, $s); 
} 
foreach my $thr (threads->list()) { 
    $thr->join(); 
} 

sub launch_thread { 
    my $s = shift; 
    my $image = Image::Magick->new(); 

    # do memory-heavy work here 

    $s->up(); 
} 

यह संस्करण ठीक शुरू होता है, लेकिन धीरे-धीरे 3.5 जीबी स्पेस मूल संस्करण का उपयोग करता है। यह सभी धागे को एक बार में चलाने से तेज़ है, लेकिन अभी भी धागे को अवरुद्ध करने से थोड़ा धीमा है।

मेरा पहला अनुमान है कि एक धागा द्वारा प्रयुक्त स्मृति में शामिल होने के लिए जब तक() मुक्त नहीं है उस पर कहा जाता है था, और के रूप में यह मुख्य थ्रेड कि ब्लॉक, कोई सूत्र मुक्त कर दिया जाता है, जब तक वे सब आवंटित किया गया है। हालांकि, पहले, कामकाजी संस्करण में, धागे गार्ड को अधिक या कम यादृच्छिक क्रम में पास करते हैं, लेकिन विपरीत क्रम में शामिल होते हैं। यदि मेरा अनुमान सही है, तो, चार चलने वाले धागे से अधिक से अधिक किसी भी समय() एड में शामिल होने का इंतजार करना चाहिए, और यह संस्करण भी धीमा होना चाहिए।

तो ये दो संस्करण इतने अलग क्यों हैं?

उत्तर

3

आपको 4 से अधिक धागे बनाने की आवश्यकता नहीं है। एक बड़ा लाभ यह है कि इसका अर्थ पर्ल दुभाषिया की 76 कम प्रतियां है। इसके अलावा, यह रीपिंग ऑर्डर को म्यूट कर देता है क्योंकि सभी धागे एक ही समय में कम या कम होते हैं।

use threads; 
use Thread::Queue qw(); 
use Image::Magick qw(); 

use constant NUM_WORKERS => 4; 

sub process { 
    my ($photo) = @_; 
    ... 
} 

{ 
    my $request_q = Thread::Queue->new(); 

    my @threads; 
    for (1..NUM_WORKERS) { 
     push @threads, async { 
      while (my $photo = $request_q->dequeue()) { 
      process($photo); 
      } 
     }; 
    } 

    $request_q->enqueue($_) for @photos; 
    $request_q->enqueue(undef) for 1..NUM_THREADS; 
    $_->join() for @threads; 
} 
+0

मैं आगे एक कतार का प्रयास करने जा रहा था। मैं सिर्फ उत्सुक हूं कि पर्ल में क्या चल रहा है जो सैमफोर का एक संस्करण पूरी तरह से काम करता है, और एक काम बहुत काम करता है। – pconley

+0

आपके संस्करण में, केवल थ्रेड जो सेमी को अनलॉक करने के लिए मिल चुके हैं, बहुत सारी मेमोरी का उपयोग करते हैं। यदि आप उन्हें पूरा करते हैं तो आप उन्हें काटते हैं, इसका मतलब है कि किसी भी समय केवल 4 धागे बहुत मेमोरी का उपयोग कर रहे हैं। यदि आप केवल अंत में उन्हें काटते हैं, तो 80 थ्रेड अंततः बहुत सारी मेमोरी का उपयोग करते हैं। – ikegami

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