2013-07-18 16 views
5

क्या किसी को जावा फाइलों के समानांतर समकक्ष के बारे में पता है। वाल्कफाइल ट्री या कुछ ऐसा ही है? यह जावा या स्कैला पुस्तकालय हो सकता है।Files.walkFileTree (जावा या स्कैला) के समानांतर संस्करण

+2

मुझे नहीं लगता कि यह समझ में आता है क्योंकि सभी समांतर धागे में समान बाधा होगी - एचडीडी। और यह नेटवर्क आईओ संचालन के रूप में समान नहीं हो सकता है। – aim

+0

समान रूप से एक अच्छा विचार में अपने फ़ाइल पेड़ क्यों चल रहा है? यह आम तौर पर आईओ बाध्य है, सीपीयू बाध्य नहीं है। –

+0

मेरे मामले में फ़ाइल प्रसंस्करण सीपीयू बाध्य है और I/O उपयोग लगभग 10% -20% है। – matt

उत्तर

3

मान लीजिए कि प्रत्येक फ़ाइल पर कॉलबैक निष्पादित करना पर्याप्त है।

यह कोड फ़ाइल सिस्टम में लूप को संभाल नहीं करेगा - आपको उस रजिस्ट्री की आवश्यकता होगी जहां आप इसके लिए गए हैं (उदा। java.util.concurrent.ConcurrentHashMap)। उन सभी प्रकार के सुधार हैं जिन्हें आप जोड़ सकते हैं, जैसे चुपचाप उन्हें अनदेखा करने की बजाय अपवादों की रिपोर्ट करना।

import java.io.File 
import scala.util._ 
def walk(f: File, callback: File => Unit, pick: File => Boolean = _ => true) { 
    Try { 
    val (dirs, fs) = f.listFiles.partition(_.isDirectory) 
    fs.filter(pick).foreach(callback) 
    dirs.par.foreach(f => walk(f, callback, pick)) 
    } 
} 

एक foreach के बजाय एक गुना का उपयोग करके फ़ाइलें एकत्रित काफी कठिन नहीं है, लेकिन मैं छोड़ कि पाठक के लिए एक व्यायाम के रूप। (ConcurrentLinkedQueue शायद उन सभी को कॉलबैक में स्वीकार करने के लिए पर्याप्त तेज़ है, भले ही आपके पास वास्तव में धीमी धागे और एक भयानक फाइल सिस्टम हो।)

+0

असल में मुझे आशा है कि 'परिपक्व-ईश' लाइब्रेरी से लिंक प्राप्त हो, जो ऐसा करता है और इसमें कुछ अतिरिक्त वायदा हैं, लेकिन आपका उदाहरण मेरी वर्तमान ज़रूरतों के लिए पर्याप्त है। धन्यवाद! – matt

7

जैसा कि अन्य ने इंगित किया है, एक फ़ाइल पेड़ चलाना लगभग निश्चित रूप से सीपीयू बाध्य की बजाय आईओ बाध्य है, इसलिए एक बहुप्रचारित फ़ाइल पेड़ चलने के लाभ संदिग्ध हैं। लेकिन अगर आप वास्तव में चाहते थे, तो आप शायद ForkJoinPool या इसी तरह के साथ अपना खुद का रोल कर सकते हैं।

import java.io.IOException; 
import java.nio.file.FileVisitResult; 
import java.nio.file.Files; 
import java.nio.file.Path; 
import java.nio.file.Paths; 
import java.nio.file.SimpleFileVisitor; 
import java.nio.file.attribute.BasicFileAttributes; 
import java.util.ArrayList; 
import java.util.List; 
import java.util.concurrent.ForkJoinPool; 
import java.util.concurrent.RecursiveAction; 

public class MultiThreadedFileTreeWalk { 
    private static class RecursiveWalk extends RecursiveAction { 
     private static final long serialVersionUID = 6913234076030245489L; 
     private final Path dir; 

     public RecursiveWalk(Path dir) { 
      this.dir = dir; 
     } 

     @Override 
     protected void compute() { 
      final List<RecursiveWalk> walks = new ArrayList<>(); 
      try { 
       Files.walkFileTree(dir, new SimpleFileVisitor<Path>() { 
        @Override 
        public FileVisitResult preVisitDirectory(Path dir, BasicFileAttributes attrs) throws IOException { 
         if (!dir.equals(RecursiveWalk.this.dir)) { 
          RecursiveWalk w = new RecursiveWalk(dir); 
          w.fork(); 
          walks.add(w); 

          return FileVisitResult.SKIP_SUBTREE; 
         } else { 
          return FileVisitResult.CONTINUE; 
         } 
        } 

        @Override 
        public FileVisitResult visitFile(Path file, BasicFileAttributes attrs) throws IOException { 
         System.out.println(file + "\t" + Thread.currentThread()); 
         return FileVisitResult.CONTINUE; 
        } 
       }); 
      } catch (IOException e) { 
       e.printStackTrace(); 
      } 

      for (RecursiveWalk w : walks) { 
       w.join(); 
      } 
     } 
    } 

    public static void main(String[] args) throws IOException { 
     RecursiveWalk w = new RecursiveWalk(Paths.get(".").toRealPath()); 
     ForkJoinPool p = new ForkJoinPool(); 
     p.invoke(w); 
    } 
} 

यह उदाहरण प्रत्येक निर्देशिका को एक अलग थ्रेड पर चलता है। जावा 7 की fork/join लाइब्रेरी के लिए यहां ट्यूटोरियल है।

+0

यदि प्रत्येक तत्व पर प्रदर्शन करने के लिए कुछ कार्यक्षमता है, तो पिछले अनुभव से फ़ाइल प्रदर्शन के दौरान महत्वपूर्ण प्रदर्शन किया जा सकता है और प्रत्येक नोड पर कार्य को क्रियात्मक रूप से बनाम बनाम कार्य निष्पादित किया जा सकता है। – Hazok

+0

@ हाज़ोक यह कार्यक्षमता पर निर्भर करता है। यदि कार्यक्षमता बहुत सीपीयू गहन है, तो यह फ़ाइल पेड़ चलने की आईओ सीमा से अधिक हो सकती है। यदि ऐसा है, तो अपना कोड समवर्ती बनाना सार्थक हो सकता है। हालांकि, यह हमेशा मामला नहीं होगा। – Jeffrey

+0

सहमत हुए, यही कारण है कि मैंने कथन का योग्यता प्राप्त की। मैं बस यह इंगित करना चाहता था कि ऐसे मामले हैं जहां प्रदर्शन लाभ प्राप्त किए जा सकते हैं क्योंकि इसे उत्तर में "संदिग्ध" कहा गया था। – Hazok

3

यह अभ्यास स्कैला उत्तर के रूप में संक्षिप्त नहीं है और न ही जावा जैसे जावा उत्तर के रूप में ।

यहां विचार था कि प्रति डिवाइस धागे की तरह कुछ समानांतर चलना शुरू करें।

वॉकर फोर्कजोइनपूल धागे पर हैं, इसलिए जब वे प्रत्येक पथ परीक्षण के लिए भविष्य को निकाल देते हैं, तो वे पूल पर फोर्क किए गए कार्य होते हैं। जब निर्देशिका निर्देशिका को पढ़ती है, तो फाइलों की तलाश करते समय निर्देशिका परीक्षण प्रबंधित अवरोधन का उपयोग करता है।

परिणाम भविष्य के पथ परीक्षण के आधार पर एक वादा पूरा करके वापस किया जाता है। (खाली हाथ पूरा करने का पता लगाने के लिए यहां कोई तंत्र नहीं है।)

एक और दिलचस्प परीक्षण में ज़िप फ़ाइलों को पढ़ने में शामिल होगा, क्योंकि डिकंप्रेशन कुछ सीपीयू खाएगा।

मुझे आश्चर्य है कि paulp will do something clever with deep listing है।

import util._ 
import collection.JavaConverters._ 
import concurrent.{ TimeoutException => Timeout, _ } 
import concurrent.duration._ 
import ExecutionContext.Implicits._ 
import java.io.IOException 
import java.nio.file.{ FileVisitResult => Result, _ } 
import Result.{ CONTINUE => Go, SKIP_SUBTREE => Prune, TERMINATE => Stop } 
import java.nio.file.attribute.{ BasicFileAttributes => BFA } 

object Test extends App { 
    val fileSystem = FileSystems.getDefault 
    val starts = (if (args.nonEmpty) args.toList else mounts) map (s => (fileSystem getPath s)) 
    val p = Promise[(Path, BFA)] 

    def pathTest(path: Path, attrs: BFA) = 
    if (attrs.isDirectory) { 
     val entries = blocking { 
     val res = Files newDirectoryStream path 
     try res.asScala.toList finally res.close() 
     } 
     List("hello","world") forall (n => entries exists (_.getFileName.toString == n)) 
    } else { 
     path.getFileName.toString == "enough" 
    } 

    def visitor(root: Path) = new SimpleFileVisitor[Path] { 
    def stopOrGo = if (p.isCompleted) Stop else Go 
    def visiting(path: Path, attrs: BFA) = { 
     future { pathTest(path, attrs) } onComplete { 
     case Success(true) => p trySuccess (path, attrs) 
     case Failure(e) => p tryFailure e 
     case _    => 
     } 
     stopOrGo 
    } 
    override def preVisitDirectory(dir: Path, attrs: BFA) = (
     if ((starts contains dir) && dir != root) Prune 
     else visiting(dir, attrs) 
    ) 
    override def postVisitDirectory(dir: Path, e: IOException) = { 
     if (e != null) p tryFailure e 
     stopOrGo 
    } 
    override def visitFile(file: Path, attrs: BFA) = visiting(file, attrs) 
    } 
    //def walk(p: Path): Path = Files walkFileTree (p, Set().asJava, 10, visitor(p)) 
    def walk(p: Path): Path = Files walkFileTree (p, visitor(p)) 

    def show(store: FileStore) = { 
    val ttl = store.getTotalSpace/1024 
    val used = (store.getTotalSpace - store.getUnallocatedSpace)/1024 
    val avail = store.getUsableSpace/1024 
    Console println f"$store%-40s $ttl%12d $used%12d $avail%12d" 
    store 
    } 
    def mounts = { 
    val devs = for { 
     store <- fileSystem.getFileStores.asScala 
     if store.name startsWith "/dev/" 
     if List("ext4","fuseblk") contains store.`type` 
    } yield show(store) 
    val devstr = """(\S+) \((.*)\)""".r 
    (devs.toList map (_.toString match { 
     case devstr(name, dev) if devs.toList exists (_.name == dev) => Some(name) 
     case s => Console println s"Bad dev str '$s', skipping" ; None 
    })).flatten 
    } 

    starts foreach (f => future (walk(f))) 

    Try (Await result (p.future, 20.seconds)) match { 
    case Success((name, attrs)) => Console println s"Result: ${if (attrs.isDirectory) "dir" else "file"} $name" 
    case Failure(e: Timeout) => Console println s"No result: timed out." 
    case Failure(t)    => Console println s"No result: $t." 
    } 
} 
+0

इस कोड को लिखने के लिए इतना समय लेने के लिए धन्यवाद। मैंने रेक्स केर समाधान को स्वीकार करने का फैसला किया क्योंकि यह बहुत संक्षिप्त है और इसे डीबग करना आसान है। – matt

+0

@lucek रेक्स सबसे अच्छा है। प्रश्न के लिए Thx, यह एपीआई की खोज मजेदार था। मैंने अन्य उत्तरों को भी ऊपर उठाया। –

संबंधित मुद्दे