2011-10-20 22 views
8

मैं इस परिदृश्य पर है में बहुत धीमी है।बड़ा सरणी हेरफेर माणिक

तो उदाहरण के लिए, मेरे पास 6000 एरे (अनुयायी सूची) हैं, प्रत्येक आकार 1 और 25000 (उनकी अनुयायी सूची) के बीच आकार में हो सकता है।

मैं आईडी के इन सभी सरणी (अनुयायियों के अद्वितीय अनुयायियों) में आईड्स की अनूठी सूची प्राप्त करना चाहता हूं। एक बार ऐसा करने के बाद मुझे आईड्स की एक और सूची (अन्य व्यक्ति अनुयायी सूची) घटाएं और अंतिम गिनती प्राप्त करें।

अद्वितीय आईडी का अंतिम सेट लगभग 60,000,000 रिकॉर्ड तक बढ़ता है। बड़ी सरणी में सरणी जोड़ने पर रूबी में, यह कुछ मिलियन के आसपास बहुत धीमी गति से शुरू होता है। सेट में जोड़ने से पहले 1 सेकंड लगते हैं, फिर 4 मिलियन से अधिक समय लेते हैं (जहां कहीं मुझे जाना है)।

मैंने जावा में एक परीक्षण कार्यक्रम लिखा और यह पूरी बात एक मिनट से भी कम समय में करती है।

शायद मैं रूबी में यह अक्षमता से कर रहा हूं, या कोई दूसरा तरीका है।

big_array = [] 
loop_counter = 0 
start_time = Time.now 
# final target size of the big array 
while big_array.length < 60000000 
loop_counter+=1 
# target size of one persons follower list 
random_size_of_followers = rand(5000) 
follower_list = [] 
follower_counter = 0 
    while follower_counter < random_size_of_followers 
    follower_counter+=1 
    # make ids very large so we get good spread and only some amt of dupes 
    follower_id = rand(240000000) + 100000 
    follower_list << follower_id 
    end 
# combine the big list with this list 
big_array = big_array | follower_list 
end_time = Time.now 

# every 100 iterations check where we are and how long each loop and combine takes. 
if loop_counter % 100 == 0 
    elapsed_time = end_time - start_time 
    average_time = elapsed_time.to_f/loop_counter.to_f 
    puts "average time for loop is #{average_time}, total size of big_array is #{big_array.length}" 
    start_time = Time.now 
end 
end 

कोई सुझाव है, यह JRuby करने के लिए स्विच और जावा के लिए इस तरह सामान ले जाने के लिए समय आ गया है: चूंकि मेरी मुख्य कोड स्वामित्व है मैं एक साधारण परीक्षण कार्यक्रम मुद्दा अनुकरण करने के लिए लिखा था है?

+0

बस करना चाहता था इंगित करें कि आपके पास अपने समय अनुभाग में 'loop_counter = 0' था। जबकि सर-एक्सेसिंग दृष्टिकोण ** हैश दृष्टिकोण के मुकाबले ** बहुत धीमा ** है, लूप समय वास्तव में तेज़ नहीं होता है। 2 मिलियन रिकॉर्ड तक, लूप टाइम मेरी मशीन पर .0 9 सेकेंड के शुरुआती लूप समय से .27 सेकेंड तक चलता है। –

+0

रुबी बहुत तेज है, आप बस इसे गलत तरीके से कर रहे हैं। यह वास्तव में डेटाबेस के लिए उपयोग-मामला है, किसी भी भाषा में इन-मेमोरी सरणी हेरफेर नहीं। डेटाबेस से बाहर निकलने से पहले एक अच्छा डीबीएम जल्दी से अलग-अलग मूल्यों और संघों को ढूंढ सकता है। मैं [सीक्वेल] (http://sequel.rubyforge.org/) को एक महान डेटाबेस ओआरएम के रूप में अनुशंसा करूंगा जो इसे बनाए रखने और क्वेरी को आसान बना देगा। –

उत्तर

5

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

यहाँ एक सरल रिफैक्टरिंग कि 100x के बारे में गति बढ़ जाती है है:

all_followers = { } 
loop_counter = 0 
start_time = Time.now 

while (all_followers.length < 60000000) 
    # target size of one persons follower list 
    follower_list = [] 

    rand(5000).times do 
    follower_id = rand(240000000) + 100000 
    follower_list << follower_id 
    all_followers[follower_id] = true 
    end 

end_time = Time.now 

# every 100 iterations check where we are and how long each loop and combine takes. 
loop_counter += 1 

    if (loop_counter % 100 == 0) 
    elapsed_time = end_time - start_time 
    average_time = elapsed_time.to_f/loop_counter.to_f 
    puts "average time for loop is #{average_time}, total size of all_followers is #{all_followers.length}" 
    start_time = Time.now 
    end 
end 

एक हैश के बारे में अच्छी बात यह है कि यह डुप्लिकेट हैं, करने के लिए असंभव है। यदि आपको किसी भी समय सभी अनुयायियों को सूचीबद्ध करने की आवश्यकता है, तो आईडी प्राप्त करने के लिए all_followers.keys का उपयोग करें।

हैश अपने ऐरे समकक्षों की तुलना में अधिक मेमोरी लेते हैं, लेकिन यह कीमत आपको प्रदर्शन के लिए भुगतान करना है। मुझे यह भी संदेह होगा कि बड़ी स्मृति उपभोक्ताओं में से एक यहां अनुयायियों की कई अलग-अलग सूचियां हैं जो उत्पन्न होती हैं और प्रतीत नहीं होतीं, इसलिए शायद आप उस चरण को पूरी तरह से छोड़ सकते हैं।

यहां महत्वपूर्ण बात यह है कि ऐरे | ऑपरेटर बहुत प्रभावी नहीं है, खासकर जब बहुत बड़े सरणी पर काम करते हैं।

+0

धन्यवाद, यह वास्तविक जीवन में आशाजनक और बहुत तेज़ लगता है, मेरे पास पहले से ही अनुयायी_लिस्ट है, इसलिए मुझे इसे हैश में जोड़ना होगा, क्या मुझे बस इसे फिर से चालू करना चाहिए और कुंजी द्वारा कुंजी डालना चाहिए: all_followers.each { | अनुयायी | all_followers [अनुयायी] = सत्य}, या उन्हें जोड़ने का एक तेज़ तरीका है। – Joelio

+2

हैश के बजाए, यदि आपके पास पहले से ही ऐरे का उपयोग है ['Set'] (http://ruby-doc.org/stdlib-1.9.2/libdoc/set/rdoc/index.html):' a = [1,2,3,3,4]; ख = [5,1,7]; सेट करें [* ए] + सेट [* बी] # => # <सेट: {1, 2, 3, 4, 5, 7}> ' – Phrogz

+0

आप सही हैं। 'सेट' लगभग पर्याप्त एक्सपोजर नहीं मिलता है। – tadman

1

यहाँ सरणी, हैश के साथ अद्वितीय वस्तुओं को संभालने के लिए एक उदाहरण है और सेट किया गया है:

require 'benchmark' 
require 'set' 
require 'random_token' 

n = 10000 

Benchmark.bm(7) do |x| 
    x.report("array:") do 
    created_tokens = [] 
    while created_tokens.size < n 
     token = RandomToken.gen(10) 
     if created_tokens.include?(token) 
     next 
     else 
     created_tokens << token 
     end 
    end 
    results = created_tokens 
    end 

    x.report("hash:") do 
    created_tokens_hash = {} 
    while created_tokens_hash.size < n 
     token = RandomToken.gen(10) 
     created_tokens_hash[token] = true 
    end 
    results = created_tokens_hash.keys 
    end 

    x.report("set:") do 
    created_tokens_set = Set.new 
    while created_tokens_set.size < n 
     token = RandomToken.gen(10) 
     created_tokens_set << token 
    end 
    results = created_tokens_set.to_a 
    end 
end 

और उनके बेंचमार्क:

   user  system  total  real 
array: 8.860000 0.050000 8.910000 ( 9.112402) 
hash:  2.030000 0.010000 2.040000 ( 2.062945) 
set:  2.000000 0.000000 2.000000 ( 2.037125) 

Refs:

ruby處理unique物件