簡體   English   中英

ExecutorService.submit( <callable> )花更多的時間?

[英]ExecutorService.submit(<callable>) taking more time?

我試圖理解java.util.concurrent包中的實用程序,並了解到我們可以將callable對象提交給ExecutorService ,它返回Future ,它在call()成功完成任務后填充了callable返回的值。方法。

我理解所有的callables都是使用多個線程並發執行的。

當我想看看ExecutorService對批處理任務執行有多大改進時,我想到了捕獲時間。

以下是我試圖執行的代碼 -

package concurrency;


import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.Callable;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;


public class ExecutorExample {

    private static Callable<String> callable = new Callable<String>() {

        @Override
        public String call() throws Exception {
            StringBuilder builder = new StringBuilder();
            for(int i=0; i<5; i++) {
                builder.append(i);
            }
            return builder.toString();
        }
    };

    public static void main(String [] args) {
        long start = System.currentTimeMillis();
        ExecutorService service = Executors.newFixedThreadPool(5);
        List<Future<String>> futures = new ArrayList<Future<String>>();
        for(int i=0; i<5; i++) {
            Future<String> value = service.submit(callable);
            futures.add(value);
        }
        for(Future<String> f : futures) {
            try {
                System.out.println(f.isDone() + " " + f.get());
            } catch (InterruptedException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            } catch (ExecutionException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            }
        }
        long end  = System.currentTimeMillis();
        System.out.println("Executer callable time - " + (end - start));
        service.shutdown();

        start = System.currentTimeMillis();
        for(int i=0; i<5; i++) {
            StringBuilder builder = new StringBuilder();
            for(int j=0; j<5; j++) {
                builder.append(j);
            }
            System.out.println(builder.toString());
        }
        end = System.currentTimeMillis();
        System.out.println("Normal time - " + (end - start));
    }

}

這是這個的輸出 -

true 01234
true 01234
true 01234
true 01234
true 01234
Executer callable time - 5
01234
01234
01234
01234
01234
Normal time - 0

如果我遺漏了某些東西或以錯誤的方式理解某些東西,請告訴我。

在此先感謝您的時間和幫助。

如果您在Callable中的任務很小,那么您將無法從並發到期任務切換和初始化開銷中獲益。 嘗試在可調用中添加更多更重的循環,比如1000000次迭代,你可以看到差異

當您第一次運行任何代碼esp時,需要時間。 如果將任務傳遞給另一個線程,則可能需要1-10微秒,如果您的任務花費的時間少於此,則開銷可能大於優勢。 即如果您的開銷足夠高,使用多個線程可能比使用單個線程慢得多。

我建議你

  • 將任務的成本增加到1000次迭代。
  • 確保在單線程示例中不丟棄結果
  • 運行兩個測試至少幾秒鍾,以確保代碼已經預熱。

不是答案(但我不確定代碼是否符合評論)。 為了擴展彼得所說的內容,通常可以找到工作規模(以執行時間衡量)的最佳位置,以平衡工作人員之間的公平工作分配的池/隊列開銷。 代碼示例有助於找到該最佳位置的估計值。 在目標硬件上運行。

import java.util.concurrent.*;
import java.util.concurrent.atomic.*;

public class FibonacciFork extends RecursiveTask<Long> {

private static final long serialVersionUID = 1L;

public FibonacciFork( long n) {
    super();
    this.n = n;
}

static ForkJoinPool fjp = new ForkJoinPool( Runtime.getRuntime().availableProcessors());

static long fibonacci0( long n) {
    if ( n < 2) {
        return n;
    }
    return fibonacci0( n - 1) + fibonacci0( n - 2);
}

static int  rekLimit = 8;

private static long stealCount;

long    n;

private long forkCount;

private static AtomicLong forks = new AtomicLong( 0);

public static void main( String[] args) {

    int n = 45;
    long    times[] = getSingleThreadNanos( n);
    System.out.println( "Single Thread Times complete");
    for ( int r = 2;  r <= n;  r++) {
        runWithRecursionLimit( r, n, times[ r]);
    }
}

private static long[] getSingleThreadNanos( int n) {
    final long times[] = new long[ n + 1];
    ExecutorService es = Executors.newFixedThreadPool( Math.max( 1, Runtime.getRuntime().availableProcessors() / 2));
    for ( int i = 2;  i <= n;  i++) {
        final int arg = i;
        Runnable runner = new Runnable() {
            @Override
            public void run() {
                long    start = System.nanoTime();
                final int minRuntime = 1000000000;
                long    runUntil = start + minRuntime;
                long    result = fibonacci0( arg);
                long    end = System.nanoTime();
                int         ntimes = Math.max( 1, ( int) ( minRuntime / ( end - start)));
                if ( ntimes > 1) {
                    start = System.nanoTime();
                    for ( int i = 0;  i < ntimes;  i++) {
                        result = fibonacci0( arg);
                    }
                    end = System.nanoTime();
                }
                times[ arg] = ( end - start) / ntimes;
            }
        };
        es.execute( runner);
    }
    es.shutdown();
    try {
        es.awaitTermination( 1, TimeUnit.HOURS);
    } catch ( InterruptedException e) {
        System.out.println( "Single Timeout");
    }
    return times;
}

private static void runWithRecursionLimit( int r, int arg, long singleThreadNanos) {
    rekLimit = r;
    long    start = System.currentTimeMillis();
    long    result = fibonacci( arg);
    long    end = System.currentTimeMillis();
    // Steals zählen
    long    currentSteals = fjp.getStealCount();
    long    newSteals = currentSteals - stealCount;
    stealCount = currentSteals;
    long    forksCount = forks.getAndSet( 0);
    System.out.println( "Fib(" + arg + ")=" + result + " in " + ( end-start) + "ms, recursion limit: " + r +
            " at " + ( singleThreadNanos / 1e6) + "ms, steals: " + newSteals + " forks " + forksCount);
}

static long fibonacci( final long arg) {
    FibonacciFork   task = new FibonacciFork( arg);
    long result = fjp.invoke( task);
    forks.set( task.forkCount);
    return result;
}

@Override
protected Long compute() {
    if ( n <= rekLimit) {
        return fibonacci0( n);
    }
    FibonacciFork   ff1 = new FibonacciFork( n-1);
    FibonacciFork   ff2 = new FibonacciFork( n-2);
    ff1.fork();
    long    r2 = ff2.compute();
    long    r1 = ff1.join();
    forkCount = ff2.forkCount + ff1.forkCount + 1;
    return r1 + r2;
}
}

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM