2013-02-11 93 views
4

我懷疑這很容易,但我不確定在Java中是否有一種天真的方式。這是我的問題,我有兩個用於處理數據的腳本,並且都有相同的輸入/輸出,除了一個是爲單個CPU編寫的,另一個是爲GPU編寫的。這項工作來自隊列服務器,我試圖編寫一個程序,將數據發送給CPU或GPU腳本,具體取決於哪一個是免費的。平衡多個隊列

我不明白如何做到這一點。

我知道用executorservice我可以指定多少個線程我想繼續運行,但不知道如何平衡兩個不同的線程。我在系統上有2個GPU和8個CPU核心,並且認爲我可以讓threadexecutorservice保持2個GPU和8個CPU進程運行,但不確定如何平衡它們,因爲GPU比CPU任務要快得多。

關於如何解決這個問題的任何建議?我是否應該創建兩個隊列,並讓他們共享以查看哪一個不太忙碌?或者是否有辦法將所有工作單元(都是相同的)放到一個隊列中,讓GPU或CPU進程從相同的隊列中取出,因爲它們是免費的?

更新:只是爲了澄清。 CPU/GPU程序不在我正在製作的程序範圍內,它們只是我通過兩種不同方法調用的腳本。我想我所問的簡化版本是兩個方法可以從同一個隊列中工作嗎?

+2

不知道你如何使用GPU,但不能你只需要10個線程(在一個ExecutorService或2 - 不知道的GPU部分)運行像'而( true){Task t = yourQueue.take(); t.run();}'?所以每個線程都可以在完成時去完成一項新任務,而不管其他人在做什麼。 – assylias 2013-02-11 15:39:59

+0

@assylias我不確定我完全理解(我可能沒有正確解釋它)。如果我有兩種方法,他們如何使用示例代碼從同一隊列中獲取數據?難道這不是把所有的工作都交給一種方法嗎? (對不起,我是Java的新手,但我還是不明白)。 – Lostsoul 2013-02-11 15:58:07

回答

2

兩種方法可以從同一隊列中工作嗎?

是的,但你應該使用BlockingQueue來節省自己的一些同步心痛。

基本上,一個選項是讓生產者通過BlockingQueue.offer將任務放入隊列中。然後設計你的CPU/GPU線程來調用BlockingQueue.take,並對他們收到的任何東西進行工作。

例如:

main (...) { 
    BlockingQueue<Task> queue = new LinkedBlockingQueue<>(); 


    for (int i=0;i<CPUs;i++) { 
     new CPUThread(queue).start(); 
    } 

    for (int i=0;i<GPUs;i++) { 
     new GPUThread(queue).start(); 
    } 

    for (/*all data*/) { 
     queue.offer(task); 
    } 
} 
class CPUThread { 
    public void run() { 
     while(/*some condition*/) { 
      Task task = queue.take(); 
      //do task work 
     } 
    } 
} 
//etc... 
1

使用的Runnable這樣的:

CPUGPURunnable implements Runnable { 
    run() { 
    if (Thread.currentThread() instance of CPUGPUThread) { 
     CPUGPUThread t = Thread.currentThread(); 
     if (t.isGPU()) 
     runGPU(); 
     else 
     runCPU(); 
    } 
    } 
} 

CPUGPUThreads是一個Thread子類,知道它在CPU或GPU模式下運行,使用的標誌。爲ThreadPoolExecutors創建一個ThreadFactory,它可以創建GPU線程的CPU。用兩名工人建立一個ThreadPoolExecutor。確保Threadfactory創建一個CPU,然後創建一個GPU線程實例。

+0

... runCPU和runGPU是將作業發送到GPU或在CPU上執行的兩種方法。 – 2013-02-11 17:10:31

+0

我假設你想在任何時候並行執行一個CPU作業和一個GPU作業。當然,如果你有多個核心並且runCPU是單線程的,那麼使用更多的工作者。 GPU一側也一樣。 – 2013-02-11 17:13:12

1

顯然有不止一種方式來做到這一點,通常最簡單的是最好的。我會建議線程池,其中一個有2個線程用於CPU任務,其次有8個線程將運行GPU任務。您的工作單位經理可以將工作提交給當前有空閒線程的池(我會建議同步該代碼塊)。標準Java ThreadPoolExecutor具有getActiveCount()方法,您可以使用它,請參閱 http://docs.oracle.com/javase/6/docs/api/java/util/concurrent/ThreadPoolExecutor.html#getActiveCount()

1

我想你有兩個代表兩個GPU的對象,其方法如boolean isFree()void execute(Runnable)。然後你應該啓動8個線程,循環從隊列中取下一個工作,放入一個免費的GPU(如果有的話),否則執行作業本身。