簡體   English   中英

在Java中使用多個線程縮短程序時間

[英]Using Multiple Threads in Java To Shorten Program Time

我沒有太多制作多線程應用程序的經驗,但我覺得我的程序可能會受益於擁有多個線程。 我正在做一個更大規模的項目,涉及使用分類器(如機器學習)來分類大約32000個客戶。 我調試了程序,發現每個用戶需要大約一秒鍾的時間。 換句話說,這需要8.8小時才能完成!

有什么方法可以運行4個線程,每個線程處理8000個用戶? 第一個線程將處理1-8000,第二個線程為8001-16000,第三個線程為16001-23000,第四個為23001-32000。 此外,截至目前,每個分類都是通過從另一個類調用靜態函數來完成的...

然后,除了主要線程之外的其他線程應該結束。 這樣的事情可行嗎? 如果是這樣,如果有人可以提供有關如何執行此操作的提示或步驟,我將非常感激。 我熟悉關鍵部分(等待/信號)的想法,但對它沒什么經驗。

再次,非常感謝任何幫助! 歡迎提出如何處理這種情況的提示和建議! 不確定它是否重要,但我有一台處理器速度為2.53 GHZ的Core 2 Duo PC。

這對於Apache Hadoop來說太輕了,每個服務器需要大約64MB的數據塊......但是對於Akka Actors來說這是一個絕佳的機會,它恰好支持Java!

http://doc.akka.io/docs/akka/2.1.4/java/untyped-actors.html

基本上,你可以讓4個演員完成這項工作,當他們完成對一個用戶或可能更好的用戶進行分類時,他們要么將它傳遞給一個“接收者”演員,它將信息放入數據結構或文件中對於輸出,或者,您可以通過每次寫入文件來執行並發I / O ..然后可以在完成所有文件后檢查/組合文件。

如果你想獲得更多的花哨/強大,你可以把演員放在遠程服務器上。 與它們進行通信仍然非常容易,並且您將利用多個服務器的CPU /資源。

我自己寫了一篇關於Akka演員的文章,但它是在Scala中,所以我會饒你的。 但是如果你谷歌“akka演員”,你會得到很多關於如何使用它的手持實例。 勇敢,潛入並進行實驗。 “演員系統”是一個容易接受的概念。 我知道你可以做到這一點!

將數據拆分為實現Runnable的對象,然后將它們傳遞給新線程。

在這種情況下擁有四個以上的線程不會殺死你,但是你不能獲得比你擁有核心更多的並行工作(如評論中所述) - 如果線程多於核心,系統將不得不處理誰去了什么時候。

如果我有一個類客戶,並且我想發布一個線程來優先考慮8000個更大集合的客戶,我可能會這樣做:

public class CustomerClassifier implements Runnable {

  private customer[] customers;

  public CustomerClassifier(customer[] customers) {
     this.customers = customers;
  }
  @Override
  public void run() {
    for (int i=0; i< customers.length; i++) {
      classify(customer);//critical that this classify function does not
                         //attempt to modify a resource outside this class
                         //unless it handles locking, or is talking to a database
                         //or something that won't throw fits about resource locking
    }
  }  
}

然后在其他地方發布這些線程

int jobSize = 8000;
customer[] customers = new customer[jobSize]();
int j = 0;
for (int i =0; i+j< fullCustomerArray.length; i++) {
  if (i == jobSize-1) {
    new Thread(new CustomerClassifier(customers)).start();//run will be invoked by thread
    customers = new Customer[jobSize]();
    j += i;
    i = 0;
  }
  customers[i] = fullCustomerArray[i+j];
}

如果你的classify方法影響同一個資源,你必須實現鎖定,並且還會在某種程度上扼殺你獲得的優勢。

並發性非常復雜,需要經過深思熟慮,我還建議查看oracle docs http://docs.oracle.com/javase/tutorial/essential/concurrency/index.html (我知道鏈接很糟糕,但希望oracle docs不會走動太多?)

免責聲明:我不是並發設計或多線程(不同主題)的專家。

如果將輸入數組拆分為4個相等的子陣列中的4個線程,則無法保證所有線程同時完成。 您最好將所有數據放在一個隊列中,讓所有工作線程從該公共隊列中提取。 使用安全的BlockingQueue實現,以便不寫低級同步/等待/通知代碼。

從java 6開始,我們有一些方便的並發工具。 您可能需要考慮使用線程池來實現更清晰的實現。

package com.threads;

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 ParalleliseArrayConsumption {

    private int[] itemsToBeProcessed ;

    public ParalleliseArrayConsumption(int size){
        itemsToBeProcessed = new int[size];
    }

    /**
     * @param args
     */
    public static void main(String[] args) {
        (new ParalleliseArrayConsumption(32)).processUsers(4);

    }

    public void processUsers(int numOfWorkerThreads){
         ExecutorService threadPool = Executors.newFixedThreadPool(numOfWorkerThreads);
         int chunk = itemsToBeProcessed.length/numOfWorkerThreads;
         int start = 0;
         List<Future> tasks = new ArrayList<Future>();
         for(int i=0;i<numOfWorkerThreads;i++){
             tasks.add(threadPool.submit(new WorkerThread(start, start+chunk)));
             start = start+chunk;
         }
             // join all worker threads to main thread
         for(Future f:tasks){
             try {
                f.get();
            } catch (InterruptedException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            } catch (ExecutionException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            }
         }

        threadPool.shutdown();
        while(!threadPool.isTerminated()){
        }

    }

    private class WorkerThread implements Callable{

        private int startIndex;
        private int endIndex;

        public WorkerThread(int startIndex, int endIndex){
            this.startIndex = startIndex;
            this.endIndex = endIndex;
        }

        @Override
        public Object call() throws Exception {
            for(int currentUserIndex = startIndex;currentUserIndex<endIndex;currentUserIndex++){
                // process the user. Add your logic here
                System.out.println(currentUserIndex+" is the user being processed in thread " +Thread.currentThread().getName());
            }
            return null;
        }       

    }

}

暫無
暫無

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

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