簡體   English   中英

發送到ExecutorService的作業的運行時間

[英]Running time of a job sent to a ExecutorService

美好的一天,

我正在編寫一個程序,其中對從文本文件讀取的每一行調用一個方法。 由於此方法的每次調用均獨立於其他任何行讀取,因此我可以並行調用它們。 為了最大限度地利用cpu,我使用ExecutorService來提交每個run()調用。 由於文本文件有1500萬行,因此我需要錯開ExecutorService運行以一次不創建太多作業(OutOfMemory異常)。 我還想跟蹤每次提交的運行的運行時間,因為我發現有些運行尚未完成。 問題是,當我嘗試將Future.get方法與超時一起使用時,超時是指它進入ExecutorService隊列的時間,而不是指它甚至從開始運行就開始運行的時間。 我想花一些時間,因為它開始運行,而不是因為它進入了隊列。

代碼如下:

ExecutorService executorService= Executors.newFixedThreadPool(ncpu);
line = reader.readLine();
long start = System.currentTimeMillis();
HashMap<MyFut,String> runs = new HashMap<MyFut, String>();
HashMap<Future, MyFut> tasks = new HashMap<Future, MyFut>();
while ( (line = reader.readLine()) != null ) { 

String s = line.split("\t")[1];
final String m = line.split("\t")[0];
MyFut f = new MyFut(s, m);
tasks.put(executorService.submit(f), f);

runs.put(f, line);

while (tasks.size()>ncpu*100){
    try {
        Thread.sleep(100);
    } catch (InterruptedException e) {
        // TODO Auto-generated catch block
        e.printStackTrace();
    }

    Iterator<Future> i = tasks.keySet().iterator();
    while(i.hasNext()){
        Future task = i.next();
        if (task.isDone()){
            i.remove();

        } else {
            MyFut fut = tasks.get(task);
            if (fut.elapsed()>10000){
                System.out.println(line);
                task.cancel(true);
                i.remove();
            }
        }
    }
}
}

private static class MyFut implements Runnable{

private long start;
String copy;
String id2;

public MyFut(String m, String id){
    super();

    copy=m;
    id2 = id;
}

public long elapsed(){
    return System.currentTimeMillis()-start;
}



@Override
public void run() {
    start = System.currentTimeMillis();
    do something...
}

}

如您所見,我嘗試跟蹤已發送的作業數,如果超過了閾值,我會稍等片刻,直到一些作業完成。 我還要嘗試檢查是否有任何作業花費太長時間才能取消它,請牢記哪個失敗,然后繼續執行。 這不是我希望的那樣。 一項任務執行10秒的時間遠遠超出了需要的時間(根據機器和CPU的數量,我會在70到130秒內完成1000行代碼)。

我究竟做錯了什么? 我的Runnable類中的run方法是否不應該僅在ExecutorService中的某些線程空閑並開始對其工作時才調用? 我得到許多結果,這些結果花費了超過10秒的時間。 有沒有更好的方法來實現我的目標?

謝謝。

如果使用的是Future,我建議將Runnable更改為Callable並返回執行線程的總時間作為結果。 下面是示例代碼:

import java.util.concurrent.Callable;

public class MyFut implements Callable<Long> {

    String copy;
    String id2;

    public MyFut(String m, String id) {
        super();

        copy = m;
        id2 = id;
    }

    @Override
    public Long call() throws Exception {
        long start = System.currentTimeMillis();
        //do something...
        long end = System.currentTimeMillis();
        return (end - start);
    }
}

您正在使工作更加努力。 Java的框架提供了您想要的一切,您只需要使用它即可。

限制待審批工作項的數目使用界隊列的作品,但ExecutorService由歸國Executors.newFixedThreadPool()使用未綁定的隊列。 一旦有界隊列已滿,要等待的策略可以通過RejectedExecutionHandler來實現。 整個過程看起來像這樣:

static class WaitingRejectionHandler implements RejectedExecutionHandler {
  public void rejectedExecution(Runnable r, ThreadPoolExecutor executor) {
    try {
      executor.getQueue().put(r);// block until capacity available
    } catch(InterruptedException ex) {
      throw new RejectedExecutionException(ex);
    }
  }
}
public static void main(String[] args)
{
  final int nCPU=Runtime.getRuntime().availableProcessors();
  final int maxPendingJobs=100;
  ExecutorService executorService=new ThreadPoolExecutor(nCPU, nCPU, 1, TimeUnit.MINUTES,
    new ArrayBlockingQueue<Runnable>(maxPendingJobs), new WaitingRejectionHandler());

  // start flooding the `executorService` with jobs here

就這樣。

測量作業所經過的時間是很容易的,因為它沒有任何關系與多線程:

long startTime=System.nanoTime();
// do your work here
long elpasedTimeSoFar = System.nanoTime()-startTime;

但是,一旦使用有限隊列,也許您就不再需要它了。


順便說Future.get帶有超時的Future.get方法引用自從它進入ExecutorService隊列以來的時間,而是引用調用get方法本身的時間。 換句話說,它告訴get方法允許等待多長時間,僅此而已。

暫無
暫無

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

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