Bagaimana cara menskalakan utas berdasarkan inti CPU?


107

Saya ingin memecahkan masalah matematika dengan banyak utas di Jawa. masalah matematika saya dapat dipisahkan menjadi unit kerja, yang ingin saya pecahkan dalam beberapa utas.

Saya tidak ingin memiliki jumlah utas yang tetap yang mengerjakannya, tetapi jumlah utas yang cocok dengan jumlah inti CPU. Masalah saya adalah, saya tidak dapat menemukan tutorial mudah di internet untuk ini. Yang saya temukan adalah contoh dengan utas tetap.

Bagaimana ini bisa dilakukan? Bisakah Anda memberikan contoh?

Jawaban:


120

Anda dapat menentukan jumlah proses yang tersedia untuk Mesin Virtual Java dengan menggunakan metode runtime statis, availableProcessors . Setelah Anda menentukan jumlah prosesor yang tersedia, buat jumlah utas itu dan bagi pekerjaan Anda sesuai dengan itu.

Pembaruan : Untuk memperjelas lebih lanjut, Thread hanyalah sebuah Objek di Java, jadi Anda dapat membuatnya seperti Anda akan membuat objek lain. Jadi, katakanlah Anda memanggil metode di atas dan menemukan bahwa ia mengembalikan 2 prosesor. Hebat. Sekarang, Anda dapat membuat loop yang menghasilkan Thread baru, dan membagi pekerjaan untuk thread tersebut, dan mengaktifkan thread tersebut. Berikut beberapa psuedocode untuk menunjukkan apa yang saya maksud:

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();
}

Untuk informasi lebih lanjut tentang membuat utas Anda sendiri, buka tutorial ini . Juga, Anda mungkin ingin melihat Thread Pooling untuk pembuatan thread.


17
Ini pada dasarnya benar, tetapi berhati-hatilah dengan kinerja pada prosesor yang dipasarkan dengan "hyper-threading" Intel. Pada quad-core, ini akan menghasilkan 8, bukan 4, tetapi kinerja Anda mungkin benar-benar mulai turun setelah 4 utas - jadi tolok ukur saya sendiri memberi tahu saya :)
xcut

Hai, oke, tidak tahu, ini mungkin. tetapi ketika saya membagi satu tugas menjadi beberapa unit kerja dan saya memerlukan solusi semua bagian untuk langkah kerja terakhir, bagaimana ini dilakukan? Ketika saya memiliki beberapa "yourThreads" bagaimana cara menggunakan join () untuk ini, karena saya tidak melihat, bagaimana beberapa utas ini dapat dibedakan? :) BTW: link Anda ke Thread Pooling arahkan saya ke ibm.com/developerworks/library/j-jtp0730.html :)
Andreas Hornig

5
Lihat contoh di sini: java.sun.com/j2se/1.5.0/docs/api/java/util/concurrent/… Ini akan memberi tahu Anda cara yang lebih efisien untuk membuat dan mengelola kumpulan utas ... Ini mungkin tampak lebih rumit pada awalnya, tetapi seperti kebanyakan hal, ini lebih rumit karena jika lebih sederhana Anda akan mencapai batasan lebih cepat.
Bill K

62

Anda mungkin ingin melihat framework java.util.concurrent untuk hal ini juga. Sesuatu seperti:

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

atau

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

Ini jauh lebih baik daripada mengatasi kumpulan utas Anda sendiri, dll.


Hai DaveC, hmmm, belum tahu sebelumnya, jadi saya akan melihat ini. Dan itu dapat diskalakan sesuai dengan inti cpu yang tersedia? Karena saya tidak bisa melihatnya dalam contoh singkat. Hormat kami, Andreas
Andreas Hornig

3
java.util.concurrent sangat scalable
Kristopher Ives

4
Kumpulan ukuran tetap dengan jumlah prosesor yang tersedia seringkali optimal untuk proses terikat CPU. Contoh pertama di sini adalah semua yang perlu Anda lakukan.
Peter Lawrey

1
Seperti yang dinyatakan dalam komentar pertama dari jawaban yang diterima, akan lebih baik menggunakan setengah dari jumlah "Prosesor" yang dilaporkan, karena dua alasan: 1. jika Anda memiliki hyper-threading, jumlah prosesor sebenarnya adalah setengah dari yang dilaporkan , dan 2. memungkinkan beberapa daya pemrosesan untuk sisa sistem berfungsi (OS dan program lain).
Matthieu

10

Pilihan 1:

newWorkStealingPool dariExecutors

public static ExecutorService newWorkStealingPool()

Membuat kumpulan utas yang mencuri pekerjaan menggunakan semua prosesor yang tersedia sebagai tingkat paralelisme targetnya.

Dengan API ini, Anda tidak perlu meneruskan jumlah inti ke ExecutorService.

Implementasi API ini dari grepcode

/**
     * 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);
    }

Pilihan 2:

newFixedThreadPool API dari Executorsatau other newXXX constructors, yang mengembalikanExecutorService

public static ExecutorService newFixedThreadPool(int nThreads)

ganti nThreads dengan Runtime.getRuntime().availableProcessors()

Opsi 3:

ThreadPoolExecutor

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

lulus Runtime.getRuntime().availableProcessors()sebagai parameter ke maximumPoolSize.



4

Cara standarnya adalah metode Runtime.getRuntime (). AvailableProcessors (). Pada kebanyakan CPU standar, Anda akan mengembalikan jumlah utas optimal (yang bukan jumlah inti CPU sebenarnya) di sini. Oleh karena itu, inilah yang Anda cari.

Contoh:

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

JANGAN lupa untuk mematikan layanan eksekutor seperti ini (atau program Anda tidak akan keluar):

service.shutdown();

Berikut adalah garis besar singkat cara mengatur kode MT berbasis masa depan (offtopic, untuk ilustrasi):

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)));
    }

Kemudian Anda perlu melacak berapa banyak hasil yang Anda harapkan dan mengambilnya seperti ini:

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

2
panggilan penutupan harus dilakukan akhirnya
Christophe Roussy

1
@ChristopheRoussy Anda benar, saya telah mengubah cuplikan sesuai, terima kasih!
fl0w

3

Di kelas Runtime, ada metode yang disebut availableProcessors (). Anda dapat menggunakannya untuk mengetahui berapa banyak CPU yang Anda miliki. Karena program Anda terikat dengan CPU, Anda mungkin ingin memiliki (paling banyak) satu utas per CPU yang tersedia.


Hai Jason dan Eric (Saya menggunakan satu komentar untuk kedua jawaban Anda, karena pada dasarnya sama). oke, itu bagus untuk diperiksa, tapi ini akan menjadi bagian pertama. Ketika saya memiliki jumlah inti, saya harus memiliki utas sebagai variabel sebagai jumlah inti ini. Saya mencoba contoh ini sebelum openbook.galileodesign.de/javainsel5/… (Jerman!) Dan menggunakan utas tetap. Tetapi saya ingin memiliki pemrograman yang sama menggunakan 2 inti dalam lingkungan inti ganda, dan 4 inti dalam lingkungan empat inti. Saya tidak ingin mengubahnya secara manual. Apakah ini mungkin? TERIMA KASIH! :)
Andreas Hornig

@Andreas - Lihat pembaruan yang saya buat pada posting saya. Saya pikir itu akan membantu memperjelas masalah.
JasCav
Dengan menggunakan situs kami, Anda mengakui telah membaca dan memahami Kebijakan Cookie dan Kebijakan Privasi kami.
Licensed under cc by-sa 3.0 with attribution required.