6

シングルスレッドのディレクトリスキャンプログラムがあります。ファイルをスキャンするとき、属性情報を読み取ってデータベースに挿入する必要があります。

2 つの質問があります。パフォーマンスを向上させるには:

  1. マルチスレッドでスキャンするには?(AndroidフォンのSDカードをスキャン)
  2. DBへのバッチ挿入を最適化するには?

以下はコードのリストです。

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]);
        }
    }
}
4

3 に答える 3

5

マルチスレッドの使用がここで役立つとは思いません。スキャン ディレクトリは IO バウンドです。複数のスレッドを使用している場合でも、それらはすべて、IO 操作が作業スレッドで完了するのを待ちます。そのため、常に 1 つのスレッド スキャンしかありません。

複数のディスクなど、ディレクトリでの IO 操作を並列化できない場合に役立ちます。

于 2013-03-04T03:17:29.470 に答える
3

はい、マルチスレッドを使用してパフォーマンスを向上させることができます。一方がディスク I/O を実行している間に、もう一方がネットワーク I/O を実行しています。これの小さな例を書きます。

これが例です。寝る前に読むほうがいいです:)クラスのコンストラクターを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++;
        }
    }

}
于 2013-03-04T03:45:16.557 に答える
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. 
于 2013-03-04T04:11:11.073 に答える