gpt4 book ai didi

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

转载 作者:行者123 更新时间:2023-12-03 12:51:35 33 4
gpt4 key购买 nike

我必须编写一个程序来读取文件中的所有单词,并确定每个单词使用了多少次。我的任务是使用多线程来加快运行时间,但是单线程程序的运行速度比多线程程序快。我曾尝试研究此问题的解决方案,但很多解释只会让我更加困惑。我对使用线程很陌生,想知道是否有人可以向我指出修复我的代码的正确方向,以便创建线程的开销不会导致程序运行速度比单个线程慢。

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


这是我的三个类(class)。有什么提示或建议吗?

最佳答案

一条经验法则说,您需要一个CPU内核用于操作系统,其他CPU内核可以用于该程序。因此,您至少需要5个CPU内核才能获得最佳性能。

创建这几个线程的开销并不重要。当您以毫秒为单位启动数十个线程时,这将变得更加相关。

代码中的主要问题是您访问共享内存区域中的数据的时间占总时间的90%。在这种情况下,我们讨论的是ConcurrentLinkedQueue和同步的Monitor.keySet()方法。当一个线程访问这些对象时,其他3个线程必须等待。长时间运行程序时,您可能会注意到只使用了总CPU能力的一小部分。

为了提高性能,我建议在启动线程之前将作业队列分成4个数据包,这样每个线程就可以处理自己的数据包,而不必等待其他线程。每个线程也应将其结果收集在单独的容器中。然后最后(线程完成之后),您可以合并四个结果。

如果您的工作线程更加复杂,那么您的问题就不会那么困难了。例如,如果对容器的访问仅花费总时间的10%(而某些计算花费90%),则线程同步的开销也将相对于总执行时间少得多。

关于java - 多线程程序花费的时间比单线程(Java)长,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/60265593/

33 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com