2013-02-20 7 views
10

से आकार के साथ डेटा के साथ डेटा के साथ व्यवहार करने वाले PyTables मैं समझने की कोशिश कर रहा हूं कि PyTables डेटा का प्रबंधन कैसे करता है जो आकार स्मृति आकार से अधिक है।मेमोरी

# Nodes referenced by a variable are kept in `_aliveNodes`. 
# When they are no longer referenced, they move themselves 
# to `_deadNodes`, where they are kept until they are referenced again 
# or they are preempted from it by other unreferenced nodes. 

इसके अलावा उपयोगी टिप्पणी _getNode विधि के अंदर पाया जा सकता है: यहाँ PyTables (link to GitHub) के कोड में टिप्पणी है।
ऐसा लगता है जैसे पीईटीबल्स के पास बहुत ही स्मार्ट आईओ बफरिंग सिस्टम है, जैसा कि मैं समझता हूं, उपयोगकर्ता द्वारा संदर्भित डेटा को "जीवित नोड्स" के रूप में संदर्भित करता है, पहले और वर्तमान में बिना संदर्भित डेटा को "मृतक" के रूप में संदर्भित करता है, जब आवश्यक हो तो इसे "पुनर्जीवित" , और डिस्क से डेटा पढ़ता है यदि अनुरोध किया गया कुंजी मृत या जीवित दोनों श्रेणियों में मौजूद नहीं है।

मुझे कुछ विशेषताओं की आवश्यकता है कि डेटा के साथ बड़े पैमाने पर उपलब्ध स्मृति के साथ काम करते समय वास्तव में पाइटेबल्स कैसे स्थितियों को संभालते हैं। मेरे विशिष्ट प्रश्न:

  1. कैसे मृत नोड/जिंदा नोड सिस्टम काम कर रहा है (सामान्य तस्वीर)?
  2. जीवित नोड्स/डेड नोड्स के बीच क्या महत्वपूर्ण अंतर है, जबकि वे दोनों सही ढंग से राम में संग्रहीत डेटा का प्रतिनिधित्व करते हैं?
  3. बफरिंग के लिए रैम की सीमा मैन्युअल रूप से समायोजित की जा सकती है? टिप्पणी के नीचे, कोड है जो params['NODE_CACHE_SLOTS'] से एक मान पढ़ता है। क्या इसे किसी उपयोगकर्ता द्वारा निर्दिष्ट किया जा सकता है? उदाहरण के लिए यदि मैं अन्य अनुप्रयोगों के लिए कुछ रैम छोड़ना चाहता हूं जिन्हें स्मृति की भी आवश्यकता है?
  4. डेटा की बड़ी मात्रा के साथ काम करते समय PyTables क्रैश या महत्वपूर्ण रूप से मंदी के दौरान स्थितियों में क्या समस्या हो सकती है? मेरे मामले में 100 गुणा से स्मृति से अधिक हो सकता है, ऐसी परिस्थितियों में आम नुकसान क्या हैं?
  5. आकार, संरचना की संरचना के अर्थ में पीईटीबल्स का उपयोग, और सर्वोत्तम प्रदर्शन प्राप्त करने के लिए 'सही' के रूप में माना जाने वाला डेटा के साथ जोड़-विमर्श?
  6. Docs suggests प्रत्येक मूल .append() चक्र के बाद .flush() का उपयोग करें। वास्तव में यह चक्र कितना समय हो सकता है? मैं SQLite और PyTables की तुलना में थोड़ा बेंचमार्क कर रहा हूं, जिसमें वे बड़ी सीएसवी फाइलों से कुंजी-मूल्य जोड़े के साथ एक विशाल तालिका बनाने में कैसे संभाल सकते हैं। और जब मैं .flush() का उपयोग करता हूं, मुख्य चक्र में कम बार, पीईटीबल्स को भारी गति मिलती है। तो - क्या यह सही है, .append() डेटा के अपेक्षाकृत बड़े हिस्से, और फिर .flush() का उपयोग करें?
+2

आप अपनी उपलब्ध रैम 100x की स्मृति में सामग्री को स्टोर नहीं कर सकते हैं। हालांकि, PyTables आपको डेटा में डेटा तक पहुंचने या स्मृति-कुशल तरीके से (कभी-कभी) में अपने डेटा में फ़ंक्शंस लागू करने में सहायता कर सकता है। आप अपने डेटा के साथ क्या करने की कोशिश कर रहे हैं? – seandavi

उत्तर

2

मेमोरी संरचना

कभी उपयोग नहीं किया pytables लेकिन स्रोत कोड देख:

class _Deadnodes(lrucacheExtension.NodeCache): 
    pass 

तो यह लग रहा है _deadnodes की तरह एक LRU कैश का उपयोग करके लागू। एलआरयू == "हाल ही में इस्तेमाल किया गया" जिसका अर्थ है कि यह पहले कम से कम इस्तेमाल नोड को फेंक देगा। स्रोत here है।

class _AliveNodes(dict): 
    ... 

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

बहुत सरल उदाहरण (नोड पत्र हैं, कैश में संख्या से संकेत मिलता है कि कैसे बासी एक प्रविष्टि है):

memory of 4, takes 1 time step 
cache with size 2, takes 5 times steps 
disk with much much more, takes 50 time steps 

get node A //memory,cache miss load from disk t=50 
get node B // "" t=100 
get node C // "" t=150 
get node D // "" t=200 
get node E // "" t=250 
get node A //cache hit load from cache t=255 
get node F //memory, cache miss load from disk t=305 
get node G //memory, cache miss load from disk t=355 
get node E // in memory t=356 (everything stays the same) 

t=200    t=250    t=255 
Memory CACHE Memory CACHE Memory CACHE 
A     E   A0  E   B0 
B     B     A 
C     C     C 
D     D     D 

t=305    t=355    
Memory CACHE Memory CACHE 
E   B1  E   G0 
A   C0  A   C1 
F     F 
D     G 

आप वास्तविक जीवन में जानते हैं इन संरचनाओं विशाल कर रहे हैं और समय यह उन तक पहुँचने के लिए लेता है बस चक्रों में, इसलिए 1/(आपके पीसी की घड़ी)।

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

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

parameters.py में DISABLE_EVERY_CYCLE, ENABLE EVERY_CYCLE और LOWEST_HIT_RATIO चर के बाद और चक्र की संख्या को फिर से सक्षम करने के लिए इंतजार LOWEST_HIT_RATIO तहत चक्रों की संख्या को परिभाषित करने के निष्क्रिय करने के लिए उपयोग किया जाता है। इन मानों को बदलना निराश है।

मुख्य बात यह है कि आपको इससे लेना चाहिए कि यदि आपको किसी बड़े डेटासेट पर प्रोसेसिंग करने की आवश्यकता है, तो सुनिश्चित करें कि वे एक ही नोड्स पर हैं। यदि आप इससे दूर हो सकते हैं, एक खंड में पढ़ सकते हैं, उस चक पर प्रसंस्करण कर सकते हैं, अपने परिणाम प्राप्त कर सकते हैं, फिर एक और हिस्सा लोड कर सकते हैं। यदि आप खंड ए लोड करते हैं, तो एक और खंड बी प्राप्त करें, फिर फिर से खंड ए लोड करें, इससे सबसे अधिक देरी होगी। केवल एक समय में डेटा के एक हिस्से पर काम करें और न्यूनतम रखें और लिखें। एक बार मान _alivenodes में है, इसे संशोधित करने में तेज़ी है, _deadnodes थोड़ा धीमा है, और न ही बहुत धीमा है।

NODE_CACHE_SLOTS

params['NODE_CACHE_SLOTS'] मृत नोड्स के सेट के आकार को परिभाषित करता है। इसे parameters.py पर वापस ट्रेस करना 64 पर डिफ़ॉल्ट है। यह बताता है कि आप अलग-अलग मानों को आजमा सकते हैं और रिपोर्ट कर सकते हैं। आप या तो फ़ाइल में मान बदल सकते हैं या कर सकते हैं:

import parameters 
parameters.NODE_CACHE_SLOTS = # something else 

यह केवल कैश में रखे नोड्स की संख्या को सीमित करता है। अतीत है कि आप पाइथन के ढेर आकार से सीमित हैं, यह सेट करने के लिए कि this देखें।

संलग्न/फ्लश

append के लिए, flush का आश्वासन दिया पंक्तियों मेज पर उत्पादन कर रहे हैं।जितना अधिक डेटा आप इस समय आगे बढ़ रहे हैं, डेटा को आंतरिक बफर से डेटा संरचना में स्थानांतरित करने के लिए लिया जाएगा। यह अन्य हैंडलिंग कोड के साथ H5TBwrite_records फ़ंक्शन के संशोधित संस्करणों को कॉल कर रहा है। मैं कॉल की लंबाई का अनुमान लगा रहा हूं जो यह निर्धारित करता है कि आउटपुट चक्र कितना समय लगता है।

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

संपादित करें:

असल pytables उनके सवाल जवाब में अपने आप को मैं this question भर में आ गए हैं कि अपनी चिंताओं से कुछ का उत्तर हो सकता है के लिए एक की जरूरत है खोजने।

मुझे इस प्रश्न का शोध करने से पहले .h5 फाइलों में आने से पहले, मुझे यह पता नहीं था कि मुझे क्या करना है, मुझे पता नहीं था कि मुझे क्या करना है।

1

मैं PyTable में एक विशेषज्ञ नहीं हूँ, लेकिन यह सबसे अधिक संभावना swap memory तरह काम करता है।

aliveNodes रैम में रहते हैं जबकि deadNodes शायद hdf5 फ़ाइलों में डिस्क पर संग्रहीत हैं (PyTables द्वारा उपयोग की जाने वाली बाइनरी फ़ाइल प्रारूप)। हर बार जब आपको डेटा के टुकड़े तक पहुंचने की आवश्यकता होती है, तो उसे रैम में होना चाहिए। तो PyTable चेक करता है अगर यह पहले से ही है (aliveNodes) और यदि यह है तो इसे आपको वापस कर देता है। अन्यथा, इसे deadNode को पुनर्जीवित करने की आवश्यकता है जहां डेटा रहता है। चूंकि रैम सीमित है, इसलिए शायद (डिस्क पर लिखें) को किसी भी कमरे को पहले से बनाने के लिए एक अप्रयुक्त aliveNode मार डालेंगे।

इस प्रक्रिया का कारण निश्चित रूप से राम का सीमित आकार है। परिणाम यह है कि जब भी आपको नोड को स्वैप करने की आवश्यकता होती है तो प्रदर्शन प्रभावित होते हैं ( को नोड और पुन: सक्रिय करें)।

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

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


अनुवाद: मैं शायद ही PyTables बारे में कुछ पता

0

मैं भी PyTable में एक विशेषज्ञ नहीं हूँ, और साइमन अच्छी तरह से अदला-बदली स्मृति की अवधारणा को कवर किया है लगता है, लेकिन यदि आप मेमोरी में फ़िट होने के लिए बहुत बड़े डेटा को संभालने के लिए डिज़ाइन किए गए एल्गोरिदम का एक ठोस उदाहरण चाहते हैं, तो मैं बाहरी प्रकार को देखने की अनुशंसा करता हूं।

मूल विचार यह है: आप स्मृति में अपने सभी डेटा को फिट नहीं कर सकते हैं, लेकिन आपको इसे सॉर्ट करने की आवश्यकता है। हालांकि, आप आकार के ब्लॉक में, स्मृति में डेटा के कुछ फिट कर सकते हैं। कहें कि ऐसे ब्लॉक हैं।

  • डेटा को आकार के ब्लॉक में विभाजित करें।
  • प्रत्येक ब्लॉक के लिए, इसे मेमोरी में लाएं और इसे सॉर्ट करें (उदा। क्विकॉर्ट या जो कुछ भी उपयोग कर रहे हों) तो इसके क्रमबद्ध संस्करण को वापस डिस्क पर लिखें।

अब, हम क्रमबद्ध डेटा के जे ब्लॉक है कि हम डेटा की एक लंबी क्रमबद्ध टुकड़ा में मर्ज करना चाहते हैं। वह समस्या विलय की तरह लगती है! तो,

  • j से प्रत्येक स्मृति में ब्लॉक हल कर से
  • उन जे मूल्यों में सबसे छोटी खोजें न्यूनतम मूल्य ले आओ। यह डेटा का सबसे छोटा टुकड़ा है! तो, हमारे सॉर्ट किए गए डेटा सेट की शुरुआत के रूप में कहीं डिस्क पर लिखें।
  • को अपने ब्लॉक से स्मृति में अगले छोटे मूल्य के साथ नया लिखित मान बदलें (यह स्वैप मेमोरी का 'स्वैपिंग' बिट है)।

अब, मेमोरी में डेटा को छोटी से छोटी ञ हैं, एक को छोड़कर हम पहले से ही अंतिम अनुसार क्रमबद्ध डिस्क पर सेट डेटा में लिखा था। इसलिए, यदि हम उस प्रक्रिया को तब तक दोहराते हैं जब तक कि सभी डेटा अंतिम सेट पर नहीं लिखा जाता है, यह हमेशा क्रमबद्ध हो जाएगा।

तो, यह केवल एक एल्गोरिदम का एक उदाहरण है जो मेमोरी में फ़िट होने के लिए डेटा को बड़े पैमाने पर संभालने के लिए मेमोरी स्वैपिंग का उपयोग करता है। PyTable की तरह के तरीकों शायद इन लाइनों के साथ हैं।

बोनस: Heresome लिंक to बाहरी प्रकार के अधिक स्पष्टीकरण हैं।