簡體   English   中英

如何在 Java 中優化這個模擬?

[英]How to optimize this simulation in Java?

我正在嘗試在 Java 中進行多線程模擬,並且我已經設法使用隊列來完成,但是執行時間很長,關於如何優化它的任何想法? 使用遞歸可以節省時間嗎?

輸入必須是這樣的:

  • 2 5 表示 5 個作業有兩個線程(worker)
  • 1 2 3 4 5 這是 integer 的作業,這意味着處理該作業的時間成本,因此 output 將是:
  • 0 0 兩個線程嘗試同時從列表中獲取作業,所以實際上索引為 0 的線程
  • 1 0 接受第一份工作並在 0 時刻開始工作
  • 0 1 1 秒后,線程 0 處理完第一個作業並從列表中取出第三個作業,並在時間 1 立即開始處理它。
  • 1 2 一秒鍾后,線程 1 完成了第二個作業並從列表中取出第四個作業,並在時間 2 立即開始處理它
  • 0 4 最后,再過 2 秒,線程 0 完成了第三個作業並從列表中取出第五個作業,並在時間 4 立即開始處理它

這是代碼:

import java.io.*;
import java.util.HashMap;
import java.util.HashSet;
import java.util.PriorityQueue;
import java.util.Set;
import java.util.StringTokenizer;

public class JobQueue {
    private int numWorkers;
    private int[] jobs;
    private int[] assignedWorker;
    private long[] startTime;

    private FastScanner in;
    private PrintWriter out;

    public static void main(String[] args) throws IOException {
        new JobQueue().solve();
    }

    private void readData() throws IOException {
        numWorkers = in.nextInt();
        int m = in.nextInt();
        jobs = new int[m];
        for (int i = 0; i < m; ++i) {
            jobs[i] = in.nextInt(); 
        }
    }

    private void writeResponse() {
        for (int i = 0; i < jobs.length; ++i) {
            out.println(assignedWorker[i] + " " + startTime[i]);
        }
    }

    private void assignJobs() {
        // TODO: replace this code with a faster algorithm.
        assignedWorker = new int[jobs.length];
         startTime = new long[jobs.length];
         PriorityQueue<Integer> nextTimesQueue = new PriorityQueue<Integer>();
         HashMap<Integer, Set<Integer>> workersReadyAtTimeT = new HashMap<Integer,Set<Integer>>();
         long[] nextFreeTime = new long[numWorkers];
         int duration = 0;
         int bestWorker = 0;
         for (int i = 0; i < jobs.length; i++) {
          duration = jobs[i];
          if(i<numWorkers) {
            bestWorker = i;
            nextTimesQueue.add(duration);
            addToSet(workersReadyAtTimeT, duration, i,0);
          }else {
            int currentTime = nextTimesQueue.poll();
            Set<Integer> workersReady = workersReadyAtTimeT.get(currentTime);
            if (workersReady.size()>1) { 
              bestWorker = workersReady.iterator().next();
              workersReady.remove(bestWorker);
              workersReadyAtTimeT.remove(currentTime);
              workersReadyAtTimeT.put(currentTime,workersReady);
              nextTimesQueue.add(currentTime);
            } else {
              bestWorker = workersReady.iterator().next();
              workersReadyAtTimeT.remove(currentTime);
              nextTimesQueue.add(currentTime+duration);
              addToSet(workersReadyAtTimeT, duration, bestWorker, currentTime);
            }
          }
          
          assignedWorker[i] = bestWorker;
          startTime[i] = nextFreeTime[bestWorker];
          nextFreeTime[bestWorker] += duration;
         }
        }
    
    private void addToSet(HashMap<Integer, Set<Integer>> workersReadyAtTimeT, int duration, int worker, int current) {
        if(workersReadyAtTimeT.get(current+duration)==null) {
          HashSet<Integer> s = new HashSet<Integer>();
          s.add(worker);
          workersReadyAtTimeT.put(current+duration, s);
        }else {
          Set<Integer> s = workersReadyAtTimeT.get(current+duration);
          s.add(worker);
          workersReadyAtTimeT.put(current+duration,s);
         }
        }

    public void solve() throws IOException {
        in = new FastScanner();
        out = new PrintWriter(new BufferedOutputStream(System.out));
        readData();
        assignJobs();
        writeResponse();
        out.close();
    }

    static class FastScanner {
        private BufferedReader reader;
        private StringTokenizer tokenizer;

        public FastScanner() {
            reader = new BufferedReader(new InputStreamReader(System.in));
            tokenizer = null;
        }

        public String next() throws IOException {
            while (tokenizer == null || !tokenizer.hasMoreTokens()) {
                tokenizer = new StringTokenizer(reader.readLine());
            }
            return tokenizer.nextToken();
        }

        public int nextInt() throws IOException {
            return Integer.parseInt(next());
        }
    }
}
 

在我看來,您的jobsList object 是完全多余的,它包含的所有內容也都在jobs數組中,當您獲取前面的元素時,您會在jobs[i]獲得項目。 為了加快一點速度,您可以將 int 的構造函數從循環中取出,並為它們分配新的數字。 另一個優化是在第一個numWorkers作業期間不進行搜索,因為您知道在您耗盡您的池之前您仍然有空閑的工人。 一旦你找到了一名優秀的工人,你就不必繼續尋找,這樣你就可以continue退出你的 for 循環。

public class JobQueue {
private int numWorkers;
private int[] jobs;
private int[] assignedWorker;
private long[] startTime;

    private void readData() throws IOException {
    numWorkers = in.nextInt();
    int m = in.nextInt();
    jobs = new int[m];
    for (int i = 0; i < m; ++i) {
        jobs[i] = in.nextInt();
    }
}

private void assignJobs() {
    assignedWorker = new int[jobs.length];
    startTime = new long[jobs.length];
    long[] nextFreeTime = new long[numWorkers];
    int duration = 0;
    int bestWorker = 0;
    for (int i = 0; i < jobs.length; i++) {
        duration = jobs[i];
        bestWorker = 0;
        if (i< numWorkers){
            bestWorker= i;
        } else{
            for (int j = 0; j < numWorkers; ++j) {
                if (nextFreeTime[j] < nextFreeTime[bestWorker])
                    bestWorker = j;
                    continue;
            }
        }
        assignedWorker[i] = bestWorker;
        startTime[i] = nextFreeTime[bestWorker];
        nextFreeTime[bestWorker] += duration;
    }
}

但是,您的解決方案和略微縮減的解決方案都需要 2 毫秒才能運行。 我還查看了使用 HashMap 來維護 NextWorker 標記,但在某些時候你趕上了它並最終每次都在尋找下一個並且不會贏得太多。

你可以嘗試有一個有序的列表/隊列,但是你有昂貴的插入而不是昂貴的搜索,你必須跟蹤時間片。 但是這樣的版本可能如下所示:

private void assignJobs() {

 assignedWorker = new int[jobs.length];
 startTime = new long[jobs.length];
 PriorityQueue<Integer> nextTimesQueue = new PriorityQueue<Integer>();
 HashMap<Integer, Set<Integer>> workersReadyAtTimeT = new HashMap<Integer,Set<Integer>>();
 long[] nextFreeTime = new long[numWorkers];
 int duration = 0;
 int bestWorker = 0;
 for (int i = 0; i < jobs.length; i++) {
  duration = jobs[i];
  if(i<numWorkers) {
    bestWorker = i;
    nextTimesQueue.add(duration);
    addToSet(workersReadyAtTimeT, duration, i,0);
  }else {
    int currentTime = nextTimesQueue.poll();
    Set<Integer> workersReady = workersReadyAtTimeT.get(currentTime);
    if (workersReady.size()>1) { 
      bestWorker = workersReady.iterator().next();
      workersReady.remove(bestWorker);
      workersReadyAtTimeT.remove(currentTime);
      workersReadyAtTimeT.put(currentTime,workersReady);
      nextTimesQueue.add(currentTime);
    } else {
      bestWorker = workersReady.iterator().next();
      workersReadyAtTimeT.remove(currentTime);
      nextTimesQueue.add(currentTime+duration);
      addToSet(workersReadyAtTimeT, duration, bestWorker, currentTime);
    }
  }
  assignedWorker[i] = bestWorker;
  startTime[i] = nextFreeTime[bestWorker];
  nextFreeTime[bestWorker] += duration;
 }
}

private void addToSet(HashMap<Integer, Set<Integer>> workersReadyAtTimeT, int duration, int worker, int current) {
if(workersReadyAtTimeT.get(current+duration)==null) {
  HashSet<Integer> s = new HashSet<Integer>();
  s.add(worker);
  workersReadyAtTimeT.put(current+duration, s);
}else {
  Set<Integer> s = workersReadyAtTimeT.get(current+duration);
  s.add(worker);
  workersReadyAtTimeT.put(current+duration,s);
 }
}

暫無
暫無

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

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