简体   繁体   English

多线程程序比单线程花费更长的时间(Java)

[英]Multi-threading program taking longer than single thread (Java)

I have to write a program that reads all of the words from a file and determines how many times each word is used.我必须编写一个程序来读取文件中的所有单词并确定每个单词的使用次数。 I'm tasked to use multi-threading to speed the run time, but the single threaded program runs faster than the multi.我的任务是使用多线程来加快运行时间,但单线程程序比多线程程序运行得更快。 I've tried researching a solution to this but a lot of the explanations are only confusing me more.我已经尝试研究解决方案,但很多解释只会让我更加困惑。 I'm very new to using threads, and was wondering if anyone could point me in the right direction of fixing my code so that the overhead for creating the threads won't cause the program to run slower than the single thread.我对使用线程非常陌生,想知道是否有人可以指出我修复代码的正确方向,以便创建线程的开销不会导致程序运行速度比单线程慢。

public class Main 
{
final static int THREADS = 4;
static HashMap<String, Integer> map = new HashMap<>();
static List<String> file = new ArrayList<String>();
static String filename = "D:\\yes.txt";
static int count;




public static void main(String args[]) throws Exception
{
    long startTime = System.nanoTime();
    Monitor m = new Monitor();
    final Queue<String> dataQueue = new ConcurrentLinkedQueue<>();

    try ( Scanner in = new Scanner(new File(filename))) 
    {
                while ( in.hasNext() ) 
                {
                    dataQueue.add( in.next() );
                }
    }
    catch ( IOException e ) 
    {
        e.printStackTrace();
    }


    Thread T1 = new Thread( new WordCount(m, map, dataQueue ));
    Thread T2 = new Thread( new WordCount(m, map, dataQueue ));
    Thread T3 = new Thread( new WordCount(m, map, dataQueue ));
    Thread T4 = new Thread( new WordCount(m, map, dataQueue ));

    T1.start();
    T2.start();
    T3.start();
    T4.start();


     //wait for threads to end
       try {
       T1.join();
       T2.join();
       T3.join();
       T4.join();
    } catch ( Exception e) {
       System.out.println("Interrupted");
    }   

    Set<String> keys = map.keySet();
    for (String key : keys) 
    {
        System.out.println(key);
        System.out.println(map.get(key));
    }
    long endTime = System.nanoTime();
    System.out.println("Thread Took "+((endTime - startTime)/100000) + " ms");


}
}
public class WordCount implements Runnable
{

    private Monitor m;
    private Queue<String> dataQueue;
    private HashMap<String, Integer> map;

    public WordCount(Monitor m, HashMap<String, Integer> map,Queue<String> dataQueue)
    {
        this.m = m;
        this.dataQueue = dataQueue;
        this.map = map;
    }

    @Override public void run()
    {
        while ( !dataQueue.isEmpty() ) 
        {
            String line = dataQueue.poll();
            m.keySet(map, line);
        }
    }   
}
public class Monitor 
{
    public synchronized void keySet(HashMap<String, Integer> map, String word) 
    {
        String[] words = filterIllegalTokens(word );
        String[] lowerCaseWords = mapToLowerCase( words );
         for ( String s : lowerCaseWords ) {


        if (map.containsKey(s)) 
        {
            map.put(s, map.get(s) + 1);

        } 
        else 
        {
            map.put(s, 1);
        }
         }
    }
    public  String[] filterIllegalTokens(String words)
    {
        List<String> filteredList = new ArrayList<>();

        if ( words.matches( "[a-zA-Z]+" ) ) {
                filteredList.add( words );
            }

        return filteredList.toArray( new String[filteredList.size()] );
    }
    public  String[] mapToLowerCase( String[] words )
    {
        String[] filteredList = new String[words.length];
        for ( int i = 0; i < words.length; i++ ) {
            filteredList[i] = words[i].toLowerCase();
        }
        return filteredList;
    }
}

These are the three classes I have.这是我的三个班级。 Any tips or advice?任何提示或建议?

A rule of thumbs says that you need one CPU core for the operating system, the others can be used for the program.根据经验,操作系统需要一个 CPU 内核,其他内核可用于程序。 So you need at least 5 CPU cores for optimal performance.因此,您至少需要 5 个 CPU 内核才能获得最佳性能。

The overhead for creating these few threads does not really matter.创建这几个线程的开销并不重要。 That would become more relevant when you start dozens of threads withing milliseconds.当您在几毫秒内启动数十个线程时,这将变得更加相关。

The main issue in your code is that you access data in a shared memory area for 90% of the total time.您代码中的主要问题是您访问共享内存区域中的数据占总时间的 90%。 In this case we are talking about the ConcurrentLinkedQueue and the synchronized Monitor.keySet() method.在这种情况下,我们讨论的是ConcurrentLinkedQueue和同步的Monitor.keySet()方法。 While one thread access these objects, the other 3 threads must wait.当一个线程访问这些对象时,其他 3 个线程必须等待。 When you run your program for a long time you might notice that only a fraction of your total CPU power is used.当您长时间运行程序时,您可能会注意到只使用了总 CPU 能力的一小部分。

To improve the performance I would recommend to split the job queue into 4 packets before you start the threads, so each thread can then process its own packet without waiting for other threads.为了提高性能,我建议在启动线程之前将作业队列拆分为 4 个数据包,这样每个线程就可以处理自己的数据包而无需等待其他线程。 Also each thread shall collect its result in an individual container.此外,每个线程都应将其结果收集在一个单独的容器中。 Then finally (after the threads are finished), you can combine the four results.然后最后(线程完成后),您可以合并四个结果。

If your worker threads would be more complicated, your problem would be less hard.如果您的工作线程更复杂,那么您的问题就不那么难了。 For example if the access to the containers would take only 10% of the overall time (while some calculation takes 90%) then the overhead of the thread synchronization would also be much less - relative to the total execution time.例如,如果对容器的访问只需要总时间的 10%(而某些计算需要 90%),那么线程同步的开销也会少得多 - 相对于总执行时间。

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

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