6

クライアントコードのベンチマークを試みています。そこで、クライアント コードのベンチマークを実行するマルチスレッド プログラムを作成することにしました。time (95 Percentile)以下の方法がどれくらいかかるかを測定しようとしています-

attributes = deClient.getDEAttributes(columnsList);

以下は、上記の方法でベンチマークを行うために私が書いたマルチスレッドコードです。私の2つのシナリオには多くのバリエーションがあります-

1) まず、 と を使用してマルチスレッド コードを使用20 threadsrunning for 15 minutesます。として 95 パーセンタイルを取得し37msます。そして、私は使用しています-

ExecutorService service = Executors.newFixedThreadPool(20);

2)しかし、使用するために同じプログラムを実行している場合15 minutes-

ExecutorService service = Executors.newSingleThreadExecutor();

それ以外の

ExecutorService service = Executors.newFixedThreadPool(20);

7msでコードを実行すると、上記の数値よりもはるかに少ない95 パーセンタイルが得られnewFixedThreadPool(20)ます。

このような高性能の問題の理由を教えてください-

newSingleThreadExecutor vs newFixedThreadPool(20)

そして、両方の方法で、プログラムを実行してい15 minutesます。

以下は私のコードです-

public static void main(String[] args) {

    try {

        // create thread pool with given size
        //ExecutorService service = Executors.newFixedThreadPool(20);
        ExecutorService service = Executors.newSingleThreadExecutor();

        long startTime = System.currentTimeMillis();
        long endTime = startTime + (15 * 60 * 1000);//Running for 15 minutes

        for (int i = 0; i < threads; i++) {
            service.submit(new ServiceTask(endTime, serviceList));
        }

        // wait for termination        
        service.shutdown();
        service.awaitTermination(Long.MAX_VALUE, TimeUnit.DAYS);
    } catch (InterruptedException e) {

    } catch (Exception e) {

    }
}

以下は、Runnable インターフェイスを実装するクラスです。

class ServiceTask implements Runnable {

    private static final Logger LOG = Logger.getLogger(ServiceTask.class.getName());
    private static Random random = new SecureRandom();

    public static volatile AtomicInteger countSize = new AtomicInteger();

    private final long endTime;
    private final LinkedHashMap<String, ServiceInfo> tableLists;

    public static ConcurrentHashMap<Long, Long> selectHistogram = new ConcurrentHashMap<Long, Long>();


    public ServiceTask(long endTime, LinkedHashMap<String, ServiceInfo> tableList) {
        this.endTime = endTime;
        this.tableLists = tableList;
    }

    @Override
    public void run() {

        try {

            while (System.currentTimeMillis() <= endTime) {

                double randomNumber = random.nextDouble() * 100.0;

                ServiceInfo service = selectRandomService(randomNumber);

                final String id = generateRandomId(random);
                final List<String> columnsList = getColumns(service.getColumns());

                List<DEAttribute<?>> attributes = null;

                DEKey bk = new DEKey(service.getKeys(), id);
                List<DEKey> list = new ArrayList<DEKey>();
                list.add(bk);

                Client deClient = new Client(list);

                final long start = System.nanoTime();

                attributes = deClient.getDEAttributes(columnsList);

                final long end = System.nanoTime() - start;
                final long key = end / 1000000L;
                boolean done = false;
                while(!done) {
                    Long oldValue = selectHistogram.putIfAbsent(key, 1L);
                    if(oldValue != null) {
                        done = selectHistogram.replace(key, oldValue, oldValue + 1);
                    } else {
                        done = true;
                    }
                }
                countSize.getAndAdd(attributes.size());

                handleDEAttribute(attributes);

                if (BEServiceLnP.sleepTime > 0L) {
                    Thread.sleep(BEServiceLnP.sleepTime);
                }
            }
        } catch (Exception e) {

        }
    }
}

更新しました:-

これが私のプロセッサ仕様です-次のように定義された2つのプロセッサを備えたLinuxマシンからプログラムを実行しています:

vendor_id       : GenuineIntel
cpu family      : 6
model           : 45
model name      : Intel(R) Xeon(R) CPU E5-2670 0 @ 2.60GHz
stepping        : 7
cpu MHz         : 2599.999
cache size      : 20480 KB
fpu             : yes
fpu_exception   : yes
cpuid level     : 13
wp              : yes
flags           : fpu vme de pse tsc msr pae mce cx8 apic sep mtrr pge mca cmov pat pse36 clflush dts acpi mmx fxsr sse sse2 ss syscall nx rdtscp lm constant_tsc arch_perfmon pebs bts rep_good xtopology tsc_reliable nonstop_tsc aperfmperf pni pclmulqdq ssse3 cx16 sse4_1 sse4_2 popcnt aes hypervisor lahf_lm arat pln pts
bogomips        : 5199.99
clflush size    : 64
cache_alignment : 64
address sizes   : 40 bits physical, 48 bits virtual
power management:
4

1 に答える 1

14

newSingleThreadExecutorvsでのこのような高パフォーマンスの問題の理由を教えてくださいnewFixedThreadPool(20)...

プロセッサよりも多くのタスク (この場合は 20) を並行して実行している場合 (20 個以上のプロセッサ ボックスがあるとは思えません)、はい、個々のタスクの完了に時間がかかります。同時に実行されている複数のスレッドを切り替えるよりも、一度に 1 つのタスクを実行する方がコンピューターにとって簡単です。プール内のスレッドの数を使用している CPU の数に制限したとしても、各タスクの実行速度はわずかではありますがおそらく遅くなります。

ただし、さまざまなサイズのスレッド プールのスループット(多数のタスクを完了するのに必要な時間) を比較すると、20 スレッドのスループットの方が高いことがわかります。20 のスレッドで 1000 のタスクを実行すると、全体として、1 つのスレッドよりもはるかに早く終了します。各タスクには時間がかかる場合がありますが、並行して実行されます。スレッドのオーバーヘッドなどを考慮すると、おそらく 20 倍高速にはなりませんが、15 倍程度高速になる可能性があります。

個々のタスクの速度について心配する必要はありませんが、プール内のスレッドの数を調整して、タスクのスループットを最大化しようとする必要があります。使用するスレッドの数は、IO の量、各タスクで使用される CPU サイクル、ロック、同期ブロック、OS で実行されている他のアプリケーション、およびその他の要因に大きく依存します。

多くの場合、スループットを最大化するために、プール内のスレッド数に関しては、CPU 数の 1 ~ 2 倍の数を開始するのに適しています。IO 要求またはスレッド ブロック操作が増えると、スレッドが追加されます。CPU バウンドが増えると、スレッドの数が減り、使用可能な CPU の数に近づきます。アプリケーションがサーバー上の他のより重要なアプリケーションと OS サイクルを競合している場合は、必要なスレッドがさらに少なくなる可能性があります。

于 2013-04-20T22:08:24.883 に答える