2012-01-18 16 views
6

मैं एक क्लाइंट विकसित कर रहा हूं जो टीसीपी पर [ईईजी] डेटा प्राप्त करेगा और इसे रिंग बफर पर लिख देगा। मैंने सोचा कि बफर को एक प्रकार या numpy सरणी के रूप में रखना बहुत सुविधाजनक हो सकता है क्योंकि ऐसे बफर के किसी भी स्थान पर एक numpy 'view' बनाना संभव है और किसी भी प्रतिलिपि संचालन के बिना डेटा को पढ़/लिख/संसाधित करना संभव है। या यह सामान्य रूप से एक बुरा विचार है?रिंग बफर numpy/ctypes

हालांकि, मुझे नहीं लगता कि इस तरह के एक निश्चित आकार के गोलाकार बफर को कैसे कार्यान्वित किया जाए। मान लीजिए मैंने एक बफर ऑब्जेक्ट बनाया है जो स्मृति में संगत है। बफर के अंत तक पहुंचने पर डेटा लिखने का सबसे अच्छा तरीका क्या है?

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

यूपीडी: उत्तर के लिए सभी को धन्यवाद। अगर किसी को भी एक ही समस्या का सामना करना पड़ता है, तो here मुझे मिला अंतिम कोड है।

+1

मैं [ 'numpy_ringbuffer' पैकेज] लिखा है (https://pypi.python.org/pypi/numpy_ringbuffer) इस समस्या है, जो एक अंतर्निहित बफर करने के लिए एक' deque' की तरह इंटरफेस प्रदान करता है हल करने के लिए – Eric

उत्तर

4

आप एन बाइट्स की एक खिड़की की जरूरत है, अपने बफर 2 * एन बाइट्स बनाने के लिए और दो स्थानों के लिए सभी इनपुट लिखें। इस तरह आप हमेशा बफर में लगातार बाइट्स रखते हैं।

data = 'Data to buffer' 
N = 4 
buf = 2*N*['\00'] 

for i,c in enumerate(data): 
    j = i % N 
    buf[j] = c 
    buf[j+N] = c 
    if i >= N-1: 
     print ''.join(buf[j+1:j+N+1]) 

प्रिंट

Data 
ata 
ta t 
a to 
to 
to b 
o bu 
buf 
buff 
uffe 
ffer 
+0

yepp। यही वह है जिसे मैं अभी लिखने की कोशिश कर रहा हूं। 2 * एन बफर के बजाय मुझे कुछ मनमानी लंबाई + एन में से एक है और एक ही विचार का पालन करें। फिर भी धन्यवाद! – dmytro

+0

यह ठीक है अगर प्रदर्शन चिंता का विषय नहीं है; लेकिन मुझे संदेह है कि यह आपके आवेदन को दिया गया है। आप शायद अपनी समस्या के वेक्टरकृत समाधान का उपयोग कर बेहतर हैं –

2

एक संभावित तरीका शुरुआत से (पहले से पुराना) बाइट्स को ओवरराइट करना प्रारंभ करना है जब लिखने वाला सूचक बफर सरणी के अंत तक पहुंचता है।

यह निश्चित आकार के अंगूठी बफर में एकमात्र विकल्प है।

मैंने पढ़ा है कि इस तरह के गोलाकार स्लाइस बनाना असंभव है।

यही कारण है कि मैं इसे एक अजीब दृश्य के साथ नहीं करूँगा। आप class रैपर को ndarray के आस-पास, बफर/सरणी, क्षमता और सूचक (सूचकांक) को सम्मिलन बिंदु पर रखकर बना सकते हैं। यदि आप एक Numpy सरणी के रूप में सामग्री प्राप्त करना चाहते हैं, तो आप ऐसा तरह एक प्रतिलिपि बनाने के लिए होगा:

buf = np.array([1,2,3,4]) 
indices = [3,0,1,2] 
contents = buf[indices] # copy 

तुम अब भी यथा-स्थान तत्वों 'मूल्यों को निर्धारित करता है, तो आप __setitem__ और __setslice__ लागू कर सकते हैं। i % N और i % N + N, जहां i एक बाइट काउंटर है:

+0

धन्यवाद। लेकिन, अगर इस तरह के हिस्से को किसी भी तरह से कॉपी किया जाना है, तो इसके बजाय संग्रह.डेक को बफर के रूप में उपयोग करने के लिए बेहतर नहीं होगा और फिर 'numpy.array (सूची (itertools.islice (buf, chstart, chend) करें)) ' ? या यह बहुत धीमा है? – dmytro

+0

मैं प्रतिलिपि से बचना चाहता था क्योंकि उस डेटा पर स्लाइडिंग विंडो एफएफटी करने का मतलब डेटा के लगभग उसी हिस्से की प्रतिलिपि बनाना होगा जब हर बार नया डेटापॉइंट आता है – dmytro

+0

@ डेमेट्रो: आपको यह मापना होगा कि 'डेक' तेज है या नहीं। मुझे डर है कि अगर आप अंगूठी बफर-संग्रहीत डेटा को सरणी में प्राप्त करना चाहते हैं तो प्रतिलिपि से बचना आसान नहीं होगा। –

-1

@Janne Karila के जवाब का एक प्रकार, सी लेकिन numpy नहीं के लिए:
अंगूठी बफर बहुत व्यापक, एन की तरह 1G x, फिर पूरे दोहरीकरण के बजाय है बात, अपनी पंक्तियों के लिए 2 * एन पॉइंटर्स की सरणी को दोहराएं। ईजी। एन = 3 के लिए, प्रारंभ

bufp = { buf[0], buf[1], buf[2], buf[0], buf[1], buf[2] }; 

तो आप केवल एक बार डेटा लिखते हैं, और anyfunc(bufp[j:j+3]) समय क्रम में buf में पंक्तियों को देखता है।

2

मुझे लगता है कि आपको यहां सी-स्टाइल सोच से एक कदम वापस लेने की आवश्यकता है। प्रत्येक प्रविष्टि के लिए एक रिंगबफर अद्यतन करना कभी भी कुशल नहीं होगा। एक रिंग-बफर मूल रूप से संगत मेमोरी ब्लॉक इंटरफ़ेस से भिन्न होता है जो numpy arrays की मांग करता है; जिसमें आप उल्लेख करते हैं कि एफएफटी शामिल है।

एक प्राकृतिक समाधान प्रदर्शन के लिए थोड़ी सी स्मृति बलिदान देना है। उदाहरण के लिए, यदि आपके बफर में रखने वाले तत्वों की संख्या एन है, तो एन + 1024 (या कुछ समझदार संख्या) की सरणी आवंटित करें। फिर आपको केवल प्रत्येक 1024 प्रविष्टियों के आस-पास एन तत्वों को स्थानांतरित करने की आवश्यकता है, और आपके पास हमेशा उपलब्ध होने पर कार्य करने के लिए एन तत्वों का एक संक्षिप्त दृश्य होता है।

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

import numpy as np 

class RingBuffer(object): 
    def __init__(self, size, padding=None): 
     self.size = size 
     self.padding = size if padding is None else padding 
     self.buffer = np.zeros(self.size+self.padding) 
     self.counter = 0 

    def append(self, data): 
     """this is an O(n) operation""" 
     data = data[-self.padding:] 
     n = len(data) 
     if self.remaining < n: self.compact() 
     self.buffer[self.counter+self.size:][:n] = data 
     self.counter += n 

    @property 
    def remaining(self): 
     return self.padding-self.counter 
    @property 
    def view(self): 
     """this is always an O(1) operation""" 
     return self.buffer[self.counter:][:self.size] 
    def compact(self): 
     """ 
     note: only when this function is called, is an O(size) performance hit incurred, 
     and this cost is amortized over the whole padding space 
     """ 
     print 'compacting' 
     self.buffer[:self.size] = self.view 
     self.counter = 0 

rb = RingBuffer(10) 
for i in range(4): 
    rb.append([1,2,3]) 
    print rb.view 

rb.append(np.arange(15)) 
print rb.view #test overflow 
+0

धन्यवाद इल्को। तो विचारों की एक सरणी बस काम नहीं करता है? लेकिन यह कैसे पता चला है, और पूरे Aptr एक फ्लैट प्रति द्वारा प्रतिस्थापित किया गया है? Aptr [0] .flags OwNDATA झूठा है, उलझन में। – denis

+0

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