100分求讨论多线程文本文件单词统计现在有一个文本文件叫做index.txt,里面有很多行,每一行都是一个文件名,
100分求讨论多线程文本文件单词统计
现在有一个文本文件叫做index.txt,里面有很多行,每一行都是一个文件名,每个文件名所指向的文件里都包含一些英文的段落(以空格隔开的单词)。现在想在读每一行的时候创建一个进程,该进程统计每个英文单词出现的次数并且最后汇总所有单词的出现次数并字母顺序打印如
apple 3
beach 1
me 5
zero 5
本人已经完成了单词统计的部分(尚未完成重复词计数),突然觉得自己的想法可能满足不了实现这个程序的要求,所以散100分和高手们讨论求点思路。如果能有高手给几段代码是最好,但是也十分欢迎一起讨论你的想法。完成部分如下:
ZhengProject4.java
- Java code
import edu.truman.cs260.Zheng.RunIndex;import edu.truman.cs260.Zheng.Counter;import edu.truman.cs260.Zheng.Word;import java.io.BufferedReader;import java.io.File;import java.io.FileNotFoundException;import java.io.FileReader;import java.io.IOException;//import java.util.ArrayList;import java.util.ArrayList;/** * @author Tian * */public class ZhengProject4 { /** * @param args */ public static void main(String[] args) { Runnable counter = new RunIndex(null); //ArrayList<String> names = new ArrayList<String>(); File file = new File("index.txt"); BufferedReader reader = null; try { reader = new BufferedReader(new FileReader(file)); String text = null; while ((text = reader.readLine()) != null) { //System.out.println(text); counter = new RunIndex(text); Thread t1 = new Thread(counter); t1.start(); } } catch (FileNotFoundException e) { e.printStackTrace(); } catch (IOException e) { e.printStackTrace(); } finally { try { if (reader != null) reader.close(); } catch (IOException e) { e.printStackTrace(); } //ArrayList <Counter> counters; //Counter counters = new Counter(null); //for (Counter counter : counters) System.out.println (counters.getCounter()+ ": "+counters.getEvent()); } }}RunIndex.java
- Java code
/** * */package edu.truman.cs260.Zheng;import java.lang.Runnable;import java.io.File;import java.util.ArrayList;/** * @author Tian * */public class RunIndex implements Runnable{ private String indexName; public RunIndex(String aIndexName) { indexName = aIndexName; } public void run() { TextReader parser=new TextReader(new File(indexName)); ArrayList <Word> words = parser.readIn(); for (Word word : words) System.out.println (word.getWord()+ ": "+word.getEvent()); }}TextReader.java:
- Java code
/** * */package edu.truman.cs260.Zheng;import java.io.BufferedReader;import java.io.File;import java.io.FileReader;import java.io.IOException;import java.util.ArrayList;import java.util.Collections; import java.util.StringTokenizer; /** * @author Tian * */public class TextReader { private File file; public TextReader (File aFile) { assert aFile.exists() && aFile.isFile(); file = aFile; } public ArrayList <Word> readIn(){ BufferedReader input = null; try { ArrayList <Word> words = new ArrayList <Word> (); input = new BufferedReader(new FileReader(file)); String line; while ((line = input.readLine()) != null) { StringTokenizer tokenizer=new StringTokenizer(line); while (tokenizer.hasMoreTokens()) { String token=tokenizer.nextToken(); Word word=new Word(token); int index=words.indexOf(word); if (index==-1) { word.increase(); words.add(word); } else words.get(index).increase(); } } input.close(); Collections.sort(words); return words; } catch (Exception e) { e.printStackTrace(); return null; } finally { if (input!= null) { try { input.close(); } catch(IOException e) { } } } } /* public void readIn () { //StringBuffer contents = new StringBuffer(); BufferedReader reader = null; ArrayList<String> names = new ArrayList<String>(); try { reader = new BufferedReader(new FileReader(file)); String text = null; String tester = null; //Iterator<String> it = names.iterator(); while ((tester = reader.readLine()) != null) { System.out.println(tester); names.add(text); } } catch (FileNotFoundException e) { e.printStackTrace(); } catch (IOException e) { e.printStackTrace(); } finally { try { if (reader != null) reader.close(); } catch (IOException e) { e.printStackTrace(); } } System.out.println(names); }*/}
Word.java:
- Java code
/** * */package edu.truman.cs260.Zheng;/** * @author Tian * */public class Word implements Comparable <Word> { private String word; private int event; public Word(String aWord) { assert aWord != null; word = aWord; } public String getWord() { return word; } public int getEvent() { return event; } public void increase(){ event++; } public boolean equals(Word another){ if (another == null) return false; if (another instanceof Word){ Word anotherWord = (Word)another; return anotherWord.getWord().equals(word); } else return false; } public int compareTo (Word aWord) { if (event < aWord.getEvent()) return -1; else if (event == aWord.getEvent()) return 0; else return 1; }} 现在主要面临的困境有两个,一是在主类中我不同进程的实现是通过一个while循环,所以我无法对他们具体控制。如果想让他们对一个全局计数变量或对象操作的话,是需要锁进程之类的吧?实在是初学,没有十分理解那部分,希望能有人指导一下怎么改写变成带锁的不同进程。二是每读一个单词,我会对Word类的一个对象进行操作,增加计数什么的,但是不同的线程是相互独立的,怎么才能让这个Word被公用呢?直接用static变量不太符合面向对象的思路,所以我不是很想用,有没有解决办法?或者有没有高手觉得根据我的要求,我程序的结构上有什么问题?欢迎大家指出!一百分求讨论。十分感谢!
[解决办法]
了解下Map/Reduce思想吧,其实跟你这个很有相似性。
总的来说,从速度考虑,不需要所有线程都操作同一个全局计数变量,这样加锁会严重限制并发能力。
建议:
1、线程数量不要太多,你的CPU没有那么多核,磁盘IO阻塞也没有达到那么严重能让你复用CPU;除非你打算用分布式,也就是多台电脑协同完成;
2、每个线程一个自己的全局计数变量,这样就不需要加锁了,性能高;
3、线程处理完毕自己所负责的文件后,就把自己的计数器返回给主线程(负责分配任务的),主线程将其计数值合并到主线程所维护的总计数器中;
4、給空闲出来的线程分配下一行(新的待处理文件)。
[解决办法]
用一个共享的map来做统计,每个线程操作这个map时,对map锁一下就可以了,不过你没一行创建一个线程,如果10万行就10万个线程,消耗系统资源,可以把每一行放到一个队列,或者多个线程一起读index文件就好了
//每一行创建一个线程的
- Java code
public class RunIndex implements Runnable{ private String indexName; private Map<Word, Integer> map; public RunIndex(String aIndexName, Map<Word, Integer> map) { indexName = aIndexName; this.map = map; } public void run() { TextReader parser=new TextReader(new File(indexName)); ArrayList <Word> words = parser.readIn(); for (Word word : words) {//System.out.println (word.getWord()+ ": "+word.getEvent()); synchronized(map) { //锁共享资源 if (map.containsKey(words)) { map.put(words, map.get(words) + 1); } else { map.put(words, 1); } } } }}public class ZhengProject4 { /** * @param args */ public static void main(String[] args) { Runnable counter = new RunIndex(null); //ArrayList<String> names = new ArrayList<String>(); File file = new File("index.txt"); BufferedReader reader = null; Map<Word, Integer> map = new HashMap<Word, Integer>(); //创建共享资源 List<Thread> list = new ArrayList<Thread>(); try { reader = new BufferedReader(new FileReader(file)); String text = null; while ((text = reader.readLine()) != null) { //System.out.println(text); counter = new RunIndex(text, map); //每个线程使用共享资源 Thread t1 = new Thread(counter); list.add(t1); t1.start(); } } catch (FileNotFoundException e) { e.printStackTrace(); } catch (IOException e) { e.printStackTrace(); } finally { try { if (reader != null) reader.close(); } catch (IOException e) { e.printStackTrace(); } //ArrayList <Counter> counters; //Counter counters = new Counter(null); //for (Counter counter : counters) System.out.println (counters.getCounter()+ ": "+counters.getEvent()); } while (true) { //等待线程执行结束 boolean end = true; for (Thread t : list) { if (t.isAlive()) { //判断每个线程是否都还活着 end = false; //有一个活着就说明还没有完全结束 break; } } if (end) break; //都没有活着的线程,说明线程都已结束 Thread.yield(); } //打印结果 for (Map.Entry<Word, Integer> e : map.entrySet()) { System.out.printf("%s, %s", e.getKey(), e.getValue()); } }}
[解决办法]
[解决办法]
2楼的想法很好!学习了!
[解决办法]
hadoop中mapreduce的demo就是关于文本文件单词统计的,楼主可以参考下。
