Làm thế nào để chia tỷ lệ luồng theo lõi CPU?


107

Tôi muốn giải quyết một vấn đề toán học với nhiều luồng trong Java. vấn đề toán học của tôi có thể được tách thành các đơn vị công việc, mà tôi muốn giải quyết trong một số chủ đề.

Tôi không muốn có một lượng luồng cố định hoạt động trên đó mà thay vào đó là một lượng luồng phù hợp với số lượng lõi CPU. Vấn đề của tôi là, tôi không thể tìm thấy một hướng dẫn dễ dàng trên internet cho việc này. Tất cả những gì tôi tìm thấy là ví dụ với các chủ đề cố định.

Điều này có thể giải quyết như thế nào? Bạn có thể cung cấp các ví dụ?

Câu trả lời:


119

Bạn có thể xác định số lượng quy trình có sẵn cho Máy ảo Java bằng cách sử dụng phương pháp Thời gian chạy tĩnh, Bộ xử lý có sẵn . Khi bạn đã xác định được số lượng bộ xử lý có sẵn, hãy tạo số luồng đó và chia nhỏ công việc của bạn cho phù hợp.

Cập nhật : Để làm rõ thêm, một Luồng chỉ là một Đối tượng trong Java, vì vậy bạn có thể tạo nó giống như bạn tạo bất kỳ đối tượng nào khác. Vì vậy, giả sử bạn gọi phương thức trên và thấy rằng nó trả về 2 bộ xử lý. Tuyệt vời. Bây giờ, bạn có thể tạo một vòng lặp để tạo một Luồng mới, và chia nhỏ công việc cho luồng đó và kích hoạt chuỗi đó. Đây là một số mã psuedocode để chứng minh ý tôi:

int processors = Runtime.getRuntime().availableProcessors();
for(int i=0; i < processors; i++) {
  Thread yourThread = new AThreadYouCreated();
  // You may need to pass in parameters depending on what work you are doing and how you setup your thread.
  yourThread.start();
}

Để biết thêm thông tin về cách tạo chuỗi của riêng bạn, hãy xem hướng dẫn này . Ngoài ra, bạn có thể muốn xem Thread Pooling để tạo các luồng.


17
Điều này về cơ bản là đúng, nhưng hãy cẩn thận về hiệu suất trên các bộ vi xử lý được bán trên thị trường với "siêu phân luồng" của Intel. Trên một quad-core, điều này sẽ trở lại 8 thay vì 4, nhưng hiệu suất của bạn thực sự có thể bắt đầu giảm sau 4 chủ đề - vì vậy tiêu chuẩn của riêng tôi cho tôi biết :)
xcut

Xin chào, được rồi, tôi không biết, điều này là có thể. nhưng khi tôi chia một nhiệm vụ thành nhiều đơn vị công việc và tôi cần tất cả giải pháp từng phần cho bước cuối cùng, thì việc này được thực hiện như thế nào? Khi tôi có một số "yourThreads", làm cách nào để sử dụng join () cho việc này, vì tôi không thấy, làm thế nào để phân biệt được một số chuỗi này? :) BTW: liên kết của bạn tới Thread Pooling dẫn tôi đến ibm.com/developerworks/library/j-jtp0730.html :)
Andreas Hornig

5
Hãy xem ví dụ ở đây: java.sun.com/j2se/1.5.0/docs/api/java/util/concurrent/… Nó sẽ cho bạn biết một cách hợp lý hơn để tạo và quản lý nhóm luồng ... Có vẻ như lúc đầu phức tạp hơn, nhưng như với hầu hết mọi thứ, nó phức tạp hơn bởi vì nếu nó đơn giản hơn, bạn sẽ sớm đạt được các giới hạn hơn.
Bill K

62

Có thể bạn cũng muốn nhìn vào khung công tác java.util.concurrent cho nội dung này. Cái gì đó như:

ExecutorService e = Executors.newFixedThreadPool(Runtime.getRuntime().availableProcessors());
// Do work using something like either
e.execute(new Runnable() {
        public void run() {
            // do one task
        }
    });

hoặc là

    Future<String> future = pool.submit(new Callable<String>() {
        public String call() throws Exception {
            return null;
        }
    });
    future.get();  // Will block till result available

Điều này tốt hơn rất nhiều so với việc đối phó với các nhóm chủ đề của riêng bạn, v.v.


Xin chào DaveC, hmmm, tôi chưa biết điều đó trước đây, vì vậy tôi sẽ xem xét điều này. Và nó có thể được chia tỷ lệ theo các lõi cpu có sẵn? Bởi vì tôi không thể thấy điều đó trong các ví dụ ngắn của bạn. Trân trọng, Andreas
Andreas Hornig

3
java.util.concurrent là khả năng mở rộng
Kristopher Ives

4
Nhóm kích thước cố định với số lượng bộ vi xử lý có sẵn thường là tối ưu cho các quy trình ràng buộc CPU. Ví dụ đầu tiên ở đây là tất cả những gì bạn cần làm.
Peter Lawrey

1
Như đã nêu trong nhận xét đầu tiên của câu trả lời được chấp nhận, tốt hơn nên sử dụng một nửa số "Bộ xử lý" được báo cáo, vì hai lý do: 1. nếu bạn có siêu phân luồng, số bộ xử lý thực bằng một nửa số được báo cáo và 2. nó cho phép một số sức mạnh xử lý cho phần còn lại của hệ thống hoạt động (HĐH và các chương trình khác).
Matthieu,

10

Lựa chọn 1:

newWorkStealingPool từExecutors

public static ExecutorService newWorkStealingPool()

Tạo một nhóm luồng đánh cắp công việc bằng cách sử dụng tất cả các bộ xử lý có sẵn làm cấp độ song song mục tiêu của nó.

Với API này, bạn không cần phải chuyển số lõi cho ExecutorService.

Triển khai API này từ mã xám

/**
     * Creates a work-stealing thread pool using all
     * {@link Runtime#availableProcessors available processors}
     * as its target parallelism level.
     * @return the newly created thread pool
     * @see #newWorkStealingPool(int)
     * @since 1.8
     */
    public static ExecutorService newWorkStealingPool() {
        return new ForkJoinPool
            (Runtime.getRuntime().availableProcessors(),
             ForkJoinPool.defaultForkJoinWorkerThreadFactory,
             null, true);
    }

Lựa chọn 2:

newFixedThreadPool API từ Executorshoặc other newXXX constructors, trả vềExecutorService

public static ExecutorService newFixedThreadPool(int nThreads)

thay thế nThreads bằng Runtime.getRuntime().availableProcessors()

Tùy chọn 3:

ThreadPoolExecutor

public ThreadPoolExecutor(int corePoolSize,
                      int maximumPoolSize,
                      long keepAliveTime,
                      TimeUnit unit,
                      BlockingQueue<Runnable> workQueue)

truyền Runtime.getRuntime().availableProcessors()dưới dạng tham số cho maximumPoolSize.



4

Cách chuẩn là phương thức Runtime.getRuntime (). AvailableProcessors (). Trên hầu hết các CPU tiêu chuẩn, bạn sẽ trả về số luồng tối ưu (không phải là số lõi CPU thực) ở đây. Do đó đây là những gì bạn đang tìm kiếm.

Thí dụ:

ExecutorService service = Executors.newFixedThreadPool(Runtime.getRuntime().availableProcessors());

Đừng quên tắt dịch vụ trình thực thi như thế này (nếu không chương trình của bạn sẽ không thoát):

service.shutdown();

Đây chỉ là một phác thảo nhanh về cách thiết lập mã MT dựa trên tương lai (offtopic, để minh họa):

CompletionService<YourCallableImplementor> completionService = 
    new ExecutorCompletionService<YourCallableImplementor>(service);
    ArrayList<Future<YourCallableImplementor>> futures = new ArrayList<Future<YourCallableImplementor>>();
    for (String computeMe : elementsToCompute) {
        futures.add(completionService.submit(new YourCallableImplementor(computeMe)));
    }

Sau đó, bạn cần theo dõi có bao nhiêu kết quả bạn mong đợi và truy xuất chúng như sau:

try {
  int received = 0;
  while (received < elementsToCompute.size()) {
     Future<YourCallableImplementor> resultFuture = completionService.take(); 
     YourCallableImplementor result = resultFuture.get();
     received++; 
  }
} finally {
  service.shutdown();
}

2
gọi tắt nên được đưa vào thử cuối cùng
Christophe Roussy

1
@ChristopheRoussy, bạn nói rất đúng, tôi đã sửa đổi đoạn mã cho phù hợp, cảm ơn bạn!
fl0w

3

Trên lớp Runtime, có một phương thức tên là readyProcessors (). Bạn có thể sử dụng nó để tìm ra bao nhiêu CPU bạn có. Vì chương trình của bạn bị ràng buộc bởi CPU, bạn có thể muốn có (nhiều nhất) một luồng cho mỗi CPU khả dụng.


Xin chào Jason và Eric (Tôi sử dụng một nhận xét cho cả hai câu trả lời của bạn, vì nó về cơ bản là giống nhau). được rồi, thật tuyệt khi kiểm tra, nhưng đây sẽ là phần đầu tiên. Khi tôi có số lượng lõi, tôi phải có các luồng thay đổi như số lượng lõi này. Tôi đã thử ví dụ này trước openbook.galileodesign.de/javainsel5/… (Tiếng Đức!) Và nó sử dụng một chuỗi cố định. Nhưng tôi muốn lập trình giống nhau bằng cách sử dụng 2 lõi trong môi trường lõi kép và 4 lõi trong môi trường lõi tứ. Tôi không muốn thay đổi nó theo cách thủ công. Điều này có khả thi không? CÁM ƠN! :)
Andreas Hornig

@Andreas - Xem các cập nhật tôi đã thực hiện cho bài đăng của mình. Tôi nghĩ rằng điều đó sẽ giúp làm rõ vấn đề.
JasCav
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.