简体   繁体   English

为什么这段Java代码没有同时运行

[英]Why this piece of Java code is not running concurrently

I have written Sieve of Eratosthenes which is supposed to work in parallel, but it's not. 我写过了Eratosthenes的筛子,它应该是平行工作的,但事实并非如此。 When I increase number of threads, time of computing is not getting lower. 当我增加线程数时,计算时间不会越来越少。 Any ideas why? 有什么想法吗?

Main class 主要课程

import java.util.Date;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

public class ConcurrentTest {
    public static void main(String[] args) throws InterruptedException {
        Sieve task = new Sieve();
        int x = 1000000;
        int threads = 4;
        task.setArray(x);
        Long beg = new Date().getTime();
        ExecutorService exec = Executors.newCachedThreadPool();
        for (int i = 0; i < threads; i++) {
            exec.execute(task);
        }
        exec.shutdown();
        Long time = 0L;
    // Main thread is waiting until all threads are terminated
    // ( it means that computing is done)
        while (true)
            if (exec.isTerminated()) {
                time = new Date().getTime() - beg;
                break;
            }

        System.out.println("Time is " + time);
    }
}

Sieve class 筛分类

import java.util.concurrent.ConcurrentHashMap;

public class Sieve implements Runnable {
    private ConcurrentHashMap<Integer, Boolean> array = 
                       new ConcurrentHashMap<Integer, Boolean>();
    private int x;
    public void run() {
        while(true){
    // I am getting synchronized number to check if it's prime
            int n = getCounter();
    // If no more numbers to check, stop loop
            if( n == -1)
                break;
    // If HashMap contains number, we can further
            if(!array.containsKey(n))continue;
            for (int i = 2 * n; i <= x; i += n) {
    // Compound numbers are removed from HashMap, Eg. 6, 12 and much more.
                    array.remove(i);
            }
        }
    }
    private synchronized int getCounter(){
        if( counter < x)
            return counter++;
        else return -1;
    }
    public void setArray(int x) {
        this.x = x;
        for (int i = 2; i <= x; i++)
            array.put(i, false);
    }
}

I made some tests with different number of threads. 我用不同数量的线程进行了一些测试。 These are results: 结果如下:

Nr of threads 1    Time is 1850, 1795, 1825
Nr of threads 2    Time is 1845, 1836, 1814
Nr of threads 3    Time is 1767, 1820, 1756
Nr of threads 4    Time is 1732, 1840, 2083
Nr of threads 5    Time is 1791, 1795, 1803
Nr of threads 6    Time is 1825, 1728, 1707
Nr of threads 7    Time is 1754, 1729, 1686
Nr of threads 8    Time is 1760, 1717, 1817
Nr of threads 9    Time is 1721, 1699, 1673
Nr of threads 10   Time is 1661, 1722, 1718

When I increase number of threads, time of computing is not getting lower 当我增加线程数时,计算时间不会越来越少

tl;dr : your problem size is too small. tl; dr :你的问题规模太小了。 If you increase x to 10000000, the differences will become more obvious. 如果将x增加到10000000,差异将变得更加明显。 They won't be what you're expecting, though. 但是,它们不会是你所期待的。

I tried your code on an eight core machine with two slight modifications: 我在八核机器上尝试了你的代码,稍作修改:

  1. For timing, I used System.nanoTime() instead of getTime() on a Date. 对于计时,我在Date上使用System.nanoTime()而不是getTime()。
  2. I used the awaitTermination method of ExecutorService rather than a spinloop to check for the end of run. 我使用了ExecutorService的awaitTermination方法而不是spinloop来检查运行的结束。

I tried launching your Sieve tasks using a fixed thread pool , a cached thread pool and a fork join pool and comparing the results of different values for your thread variable. 我尝试使用固定线程池缓存线程池fork连接池启动Sieve任务,并比较线程变量的不同值的结果。

I see the following results (in milliseconds) on my machine with x=10000000: 我在x = 10000000的机器上看到以下结果(以毫秒为单位):

Thread count      = 1    2    4    8    16
    Fixed thread pool = 5451 3866 3639 3227 3120
    Cached thread pool= 5434 3763 3709 3258 3078
    Fork-join pool    = 6732 3670 3735 3190 3102

What these results show us is a clear benefit of changing from a single thread of execution to two threads. 这些结果向我们展示了从单个执行线程更改为两个线程的明显好处。 However, the benefit of additional threads drops off rapidly. 但是,额外线程的好处会迅速下降。 There's an interesting plateau going from two to four threads and marginal benefits up to 16. 有一个有趣的高原,从两到四个线程,边际利益高达16。

In addition, you can also see that the different threading mechanisms have different initial overhead: I didn't expect the Fork-Join pool to cost that much more to start than the other mechanisms. 此外,您还可以看到不同的线程机制具有不同的初始开销:我没想到Fork-Join池比其他机制花费更多的开始。

So, as written, you shouldn't really expect a benefit past two threads for small but non-trivial problem sets. 因此,正如所写的那样,对于小而重要的问题集,你不应该期望通过两个线程获益。

If you'd like to increase the benefit of additional threads, you're going to need to look at your current implementation. 如果您想增加额外线程的好处,那么您将需要查看当前的实现。 For example, when I switched from your synchronized getCounter() to an AtomicInteger using incrementAndGet() , I eliminated the overhead of the synchronized method. 例如,当我使用incrementAndGet()从synchronized getCounter()切换到AtomicInteger时 ,我消除了synchronized方法的开销。 The result is that all of my four thread numbers dropped on the order of 1000 milliseconds. 结果是我的所有四个线程数都下降了1000毫秒。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM