2013-08-15 5 views
5

में रेगेक्स संकलित करना मेरे पास एक ऐसा प्रोग्राम है जहां मुझे कई हज़ार बड़े रेगेक्स संकलित करने की आवश्यकता है, जिनमें से सभी का उपयोग कई बार किया जाएगा। समस्या यह है कि, यह बहुत लंबा लगता है (cProfiler, 113 सेकेंड के अनुसार) re.compile() उन्हें। , (Btw, वास्तव में इन regexes < 1.3 सेकेंड में एक बार संकलित के सभी का उपयोग करके खोज।)पायथन: समांतर

अगर मैं precompile नहीं है, यह सिर्फ करने के लिए जब मैं वास्तव में खोज समस्या स्थगित के बाद से re.search(expr, text) परोक्ष expr संकलित करता है। दरअसल, यह बदतर है, क्योंकि re हर बार जब मैं उनका उपयोग करता हूं तो regexes की पूरी सूची को पुन: संकलित करने जा रहा है।

मैंने multiprocessing का उपयोग करने का प्रयास किया, लेकिन वास्तव में चीजों को धीमा कर देता है।

## rgxparallel.py ## 
import re 
import multiprocessing as mp 

def serial_compile(strings): 
    return [re.compile(s) for s in strings] 

def parallel_compile(strings): 
    print("Using {} processors.".format(mp.cpu_count())) 
    pool = mp.Pool() 
    result = pool.map(re.compile, strings) 
    pool.close() 
    return result 

l = map(str, xrange(100000)) 

और मेरे परीक्षण स्क्रिप्ट:

#!/bin/sh 
python -m timeit -n 1 -s "import rgxparallel as r" "r.serial_compile(r.l)" 
python -m timeit -n 1 -s "import rgxparallel as r" "r.parallel_compile(r.l)" 
# Output: 
# 1 loops, best of 3: 6.49 sec per loop 
# Using 4 processors. 
# Using 4 processors. 
# Using 4 processors. 
# 1 loops, best of 3: 9.81 sec per loop 

मेरा अनुमान है कि कि समानांतर संस्करण है:

  1. समानांतर में, संकलन और regexes नमकीन बनाना यहाँ एक छोटे से परीक्षण प्रदर्शन करने के लिए है , ~ 2 सेकंड
  2. सीरियल में, अन-पिकलिंग, और इसलिए उन सभी को पुन: संकलित करना, ~ 6.5 सेकंड
एक साथ शुरू करने और प्रक्रियाओं को रोकने के लिए भूमि के ऊपर के साथ

, multiprocessing 4 पर प्रोसेसर 25% से अधिक धीमी धारावाहिक से है।

मैंने अलग-अलग अभिव्यक्तियों के बजाय, उप-सूचियों में 0xऔर pool.map में रेगेक्स की सूची को विभाजित करने का भी प्रयास किया। इसने एक छोटा प्रदर्शन बढ़ावा दिया, लेकिन मैं अभी भी धारावाहिक से ~ 25% धीमी गति से बेहतर नहीं हो सका।

क्या धारावाहिक से तेज़ संकलन करने का कोई तरीका है?

संपादित करें: रेगेक्स संकलन के चलने वाले समय को सही किया गया।

मैंने threading का उपयोग करने का भी प्रयास किया, लेकिन जीआईएल के कारण, केवल एक प्रोसेसर का उपयोग किया गया। यह multiprocessing (130 सेक बनाम 136 सेकेंड) से थोड़ा बेहतर था, लेकिन सीरियल (113 सेकंड) से अभी भी धीमा है।

संपादित करें 2: मैंने महसूस किया कि कुछ regexes दोहराया होने की संभावना थे, इसलिए मैं उन्हें कैशिंग के लिए एक dict गयी। यह ~ 30 सेकंड बंद कर दिया। हालांकि, मैं अभी भी समानांतर में रूचि रखता हूं। लक्ष्य मशीन में 8 प्रोसेसर हैं, जो संकलन समय को ~ 15 सेकेंड तक कम कर देंगे।

+0

आपके पास इतने सारे बड़े regexes कैसे हैं और केवल उनके साथ बहुत कम खोज करते हैं? क्या आप उन्हें सरल बना सकते हैं, शायद उन्हें पुराने पुराने स्ट्रिंग मैनिपुलेशन के साथ प्रतिस्थापित करें, या उनमें से कुछ को चलाने से बचें? – delnan

+0

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

+0

क्या आपने इसके बजाय धागे का उपयोग करने का प्रयास किया है? प्रति सीपीयू 1 धागा और रेगेक्स उनके बीच विभाजित है? रेगेक्स सी में लागू किया गया है ताकि आपको जीआईएल के बावजूद समांतरता का सभ्य स्तर मिलना चाहिए। – tdelaney

उत्तर

0

जितना मैं अजगर प्यार करता हूँ, मैं

आप अजगर में मुख्य कार्यक्रम रखना चाहते हैं, तो आप subprocess इस्तेमाल कर सकते हैं एक कॉल करने के लिए लगता है कि समाधान है, यह पर्ल (see this speed comparison, for example), या सी में करते हैं, आदि perl स्क्रिप्ट (केवल subprocess कॉल के रूप में जितना संभव हो सके उतने मानों को पार करना सुनिश्चित करें।