मेरे पास कुछ स्थितियां हैं जहां मुझे फ़ाइलों को बार-बार सूचीबद्ध करने की आवश्यकता है, लेकिन मेरे कार्यान्वयन धीमे हो गए हैं। मेरे पास 92784 फाइलों के साथ एक निर्देशिका संरचना है। find
फ़ाइलों को 0.5 सेकंड से कम समय में सूचीबद्ध करता है, लेकिन मेरा हास्केल कार्यान्वयन बहुत धीमा है।निर्देशिकाओं को तेजी से कैसे सूचीबद्ध करें?
मेरा पहला कार्यान्वयन पूरा करने के लिए 9 सेकंड से थोड़ा अधिक समय ले गया, अगले संस्करण 5 सेकंड से थोड़ा अधिक और मैं वर्तमान में दो सेकंड से थोड़ा कम नीचे हूं।
listFilesR :: FilePath -> IO [FilePath]
listFilesR path = let
isDODD "." = False
isDODD ".." = False
isDODD _ = True
in do
allfiles <- getDirectoryContents path
dirs <- forM allfiles $ \d ->
if isDODD d then
do let p = path </> d
isDir <- doesDirectoryExist p
if isDir then listFilesR p else return [d]
else return []
return $ concat dirs
परीक्षण स्मृति के बारे में 100 मेगाबाइट (+ आरटीएस -s) लेता है, और कार्यक्रम जीसी में 40% के आसपास खर्च करता है।
मैं अनुक्रम के साथ एक राइटरट मोनैड में लिस्टिंग करने की सोच रहा था, जो कि कॉन्सट्स और सूची निर्माण को रोकने के लिए मोनॉयड के रूप में था। क्या यह संभवतः मदद करता है? मुझे और क्या करना चाहिए?
संपादित करें: मैंने readDirStream का उपयोग करने के लिए फ़ंक्शन को संपादित किया है, और यह स्मृति को नीचे रखने में मदद करता है। अभी भी कुछ आवंटन हो रहा है, लेकिन उत्पादकता दर> 9 5% है और यह एक सेकंड से भी कम समय में चलती है।
यह वर्तमान संस्करण है:
list path = do
de <- openDirStream path
readDirStream de >>= go de
closeDirStream de
where
go d [] = return()
go d "." = readDirStream d >>= go d
go d ".." = readDirStream d >>= go d
go d x = let newpath = path </> x
in do
e <- doesDirectoryExist newpath
if e
then
list newpath >> readDirStream d >>= go d
else putStrLn newpath >> readDirStream d >>= go d
मैंने System.Posix.Directory और iteratees का उपयोग करके एक संस्करण बनाया है, अगर यह बेहतर होता तो यह बहुत कुछ नहीं करता था। मुझे मिली एक अजीब बात यह थी कि System.Posix.Directory मुझे लगता है कि कार्यक्षमता प्रदान करने के लिए प्रतीत नहीं होता है।"readdir" एक "संरचना dirent" के लिए एक सूचक देता है, लेकिन ऐसा लगता है कि आप निर्देशिका स्ट्रीम से प्राप्त कर सकते हैं एकमात्र चीज फ़ाइल नाम है - जिसका अर्थ है कि आपको एक और कॉल करना है (संभवतः statDirectoryExist के माध्यम से stat() के लिए) यह एक निर्देशिका है। यह समस्या का एक हिस्सा भी हो सकता है - खोजने के लिए किसी अन्य सिस्कोल को खोजने की आवश्यकता नहीं है कि यह निर्देशिका है या नहीं। – mokus
@mokus: जानकारी के लिए धन्यवाद। पॉज़िक्स सिस्टम में, [readdir] (http://www.opengroup.org/onlinepubs/009695399/functions/readdir.html) द्वारा निर्देशिका पढ़ना वापस नहीं आता है कि लौटाई गई प्रविष्टि एक निर्देशिका है या नहीं, और इसलिए आपको एक अलग की आवश्यकता है syscall (आमतौर पर स्टेट या lstat) यह तय करने के लिए कि यह एक निर्देशिका है या नहीं। इसलिए, आपके द्वारा वर्णित System.Posix.Directory का व्यवहार अजीब नहीं है। खोज कमांड के कुछ कार्यान्वयन हार्ड-लिंक-गिनती चाल का उपयोग करते हैं ताकि अस्थायी कॉल को स्टेट को छोड़ दिया जा सके, जो ट्रैवर्सल को तेज़ी से बनाता है। –
मेरे सिस्टम (मैक ओएस) पर, "स्ट्रेट dirent" में एक फ़ील्ड "d_type" है, जिसका एक संभावित मान "DT_DIR" है। विकिपीडिया संकेत देता है कि यह POSIX spec में वैकल्पिक है, लेकिन यह सुनिश्चित है कि निर्देशिकास्ट्रीम के लिए 'isDir' या 'fileType' ऑपरेशन प्रदान करने के लिए यह एक मजबूत मामला होगा जो उपलब्ध होने पर उस जानकारी का उपयोग करेगा और अन्यथा कॉल कॉल करेगा। यहां तक कि यदि यह आवश्यक मानक नहीं है, यदि उसके प्लेटफ़ॉर्म में यह है, तो मुझे लगता है कि अगर इसका उपयोग नहीं हो रहा है तो मुझे आश्चर्य होगा। – mokus