2013-03-04 2 views
4

У меня есть программа сканирования каталога с одним потоком. При сканировании файла я должен прочитать информацию об атрибутах и ​​вставить его в базу данных.Как сканировать каталог с несколькими потоками

У меня есть 2 вопроса. В целях повышения эффективности:

  1. Как сканировать с помощью многопоточного? (сканирование SD-карты телефона Android)
  2. Как оптимизировать пакетную вставку в БД?

Ниже приведен код листинга:

void scan() { 
    File file = new File("/mnt/sdcard"); 
    fun(file); 
} 

void fun(File file) { 
    if (!file.exists()) { 
     return; 
    } 
    if (!file.isDirectory()) { 
     // read attribute information and insert to db 
     return; 
    } else { 
     File[] arr = file.listFiles(); 
     for (int i = 0; i < arr.length; i++) { 
      fun(arr[i]); 
     } 
    } 
} 
+0

Вы должны задать один вопрос в то время, это как вопросы наиболее полезными для других. Особенно, когда они полностью не связаны –

ответ

1

Да, вы можете увеличить производительность, используя многопоточность, в то время как один делает ввод-вывод на диск другим, который делает сетевой ввод-вывод, я напишу небольшой пример этого.

вот пример, лучше, чем читать перед сном :) с конструктором класса ReadThenAll(5); вы создаете 5 потоков для изучения папок и подпапок. повеселись !!

package foo; 

import java.io.File; 
import java.util.Queue; 
import java.util.concurrent.ConcurrentLinkedQueue; 

public class ReadThenAll { 

    // subfolders to explore 
    private final Queue exploreList = new ConcurrentLinkedQueue(); 

    private long counter = 0; 

    public void count() { 
     counter++; 
    } 

    public static void main(String[] args) { 

     ReadThenAll me = new ReadThenAll(5); 
     me.scan("/tmp"); 

    } 

    int[] threads; 

    public ReadThenAll(int numberOfThreads) { 
     threads = new int[numberOfThreads]; 

     for (int i = 0; i < threads.length; i++) { 
      threads[i] = -1; 
     } 
    } 

    void scan(String fileName) { 

     final long start = System.currentTimeMillis(); 

     // add the first one to the list 
     File file = new File(fileName); 
     exploreList.add(file); 

     for (int i = 0; i < threads.length; i++) { 
      FileExplorer explorer = new FileExplorer(i, this); 
      Thread t = new Thread(explorer); 
      t.start(); 
     } 

     Thread waitToFinish = new Thread(new Runnable() { 

      @Override 
      public void run() { 

       boolean working = true; 
       while (working) { 
        working = false; 

        for (int i = 0; i < threads.length; i++) { 
         if (threads[i] == -1) { 
          working = true; 
          break; 
         } 
        } 

        try { 
         Thread.sleep(2); 
        } catch (InterruptedException e) { 
         e.printStackTrace(); 
        } 
       } 

       long elapsed = System.currentTimeMillis() - start; 
       System.out.println("total time (ms) : " + elapsed); 

      } 
     }); 

     waitToFinish.start(); 
    } 

    public void done(int id, int counter) { 
     threads[id] = counter; 
    } 

    class FileExplorer implements Runnable { 

     public int counter = 0; 
     public ReadThenAll owner; 
     private int id; 

     public FileExplorer(int id, ReadThenAll owner) { 
      this.id = id; 
      this.owner = owner; 
     } 

     @Override 
     public void run() { 
      while (!owner.exploreList.isEmpty()) { 

       // get the first from the list 
       try { 
        File file = (File) owner.exploreList.remove(); 

        if (file.exists()) { 

         if (!file.isDirectory()) { 
          doThemagic(file); 
         } else { 

          // add the files to the queue 
          File[] arr = file.listFiles(); 
          if (arr != null) { 
           for (int i = 0; i < arr.length; i++) { 
            owner.exploreList.add(arr[i]); 
           } 
          } 
         } 
        } 
       } catch (Exception e) { 
        e.printStackTrace(); 
        // silent kill :) 
       } 

       try { 
        Thread.sleep(1); 
       } catch (InterruptedException e) { 
        e.printStackTrace(); 
       } 
      } 

      owner.done(id, counter); 
      System.out.println("total of files : " + counter); 
     } 

     private void doThemagic(File file) { 
      System.out.println(file.toString()); 
      counter++; 
     } 
    } 

} 
+0

большое спасибо – user2130265

2

Я не думаю, что с помощью многопоточного собирается помочь здесь. Сканирующий каталог ограничен IO. Даже если вы используете несколько потоков, все они ждут завершения операции ввода-вывода в рабочем потоке. Поэтому в любое время есть только одно сканирование потоков.

Это поможет, если операция IO в вашем каталоге не может быть распараллелена, например. несколько дисков ..

+0

большое спасибо. – user2130265

+0

@ user2130265 вы могли бы принять его как ответ, который мог бы увеличить мои «точки репутации» :) – zzk

+1

Фактически, чтение атрибутов файлов может быть быстрее при использовании нескольких потоков, потому что это только запрос к файловой системе, а не чтение файлов по всему диску , но, единственный способ доказать это - попробовать. –

1

вы можете следовать ниже одной конструкции

1 - Create a queue in which supports multiple read and single write. 
2- Get the number of cpu in the system in which you need to run the program because you can not run more threads simultaneously. 

3- I/O is always blocking if you have 2 threads which are writing on Disk then they have to be serialized or you have multiple physical storage devices so you can access those. 

4- The Queue you created in step 1 , you can write into the queue and simultaneously read. 

5- Again database operation is blocking one that means your thread has to wait until it got the response from the db server rather than blocking the thread you can think of asynchronous processing and callback mechanism. 
+0

большое спасибо – user2130265