- html - 出于某种原因,IE8 对我的 Sass 文件中继承的 html5 CSS 不友好?
- JMeter 在响应断言中使用 span 标签的问题
- html - 在 :hover and :active? 上具有不同效果的 CSS 动画
- html - 相对于居中的 html 内容固定的 CSS 重复背景?
我用 Java 实现了一个字数统计程序。基本上,该程序需要一个大文件(在我的测试中,我使用了一个仅包含数字的 10 GB 数据文件),并计算每个“单词”出现的次数 - 在这种情况下,一个数字(例如 23723 可能会出现文件中的 243 次)。
下面是我的实现。我试图改进它,主要考虑性能,但也有一些其他的东西,我正在寻找一些指导。以下是我希望纠正的一些问题:
目前,该程序已线程化并正常运行。但是,我所做的是将一大块内存 (500MB/NUM_THREADS)
传递给每个线程,然后每个线程进行 wordcount。这里的问题是我让主线程等待所有线程完成,然后再将更多数据传递给每个线程。这不是什么太大的问题,但是有一段时间会有一些线程等待并且有一段时间什么都不做。我相信某种类型的工作池或执行程序服务可以解决这个问题(我还没有学过这方面的语法)。
该程序仅适用于包含整数的文件。那是个问题。我为此苦苦挣扎,因为我不知道如何在不创建大量未使用变量的情况下迭代数据(使用 String 甚至 StringBuilder 的性能很糟糕)。目前,我使用的事实是我知道输入是一个整数,并且只是将临时变量存储为 int
,所以那里没有内存问题。我希望能够使用某种分隔符,无论该分隔符是空格还是多个字符。
我正在使用全局 ConcurrentHashMap 来描述键值对。例如,如果线程找到数字“24624”,它会在映射中搜索该数字。如果它存在,它将将该键的值增加一。末尾键的值表示该键出现的次数。那么这是正确的设计吗?我可以通过为每个线程提供自己的 HashMap 然后在最后将它们全部合并来提高性能吗?
有没有其他方法可以在不使用 RandomAccessMemory 类的情况下通过偏移量查找文件?这个类只会读入一个字节数组,然后我必须转换它。我没有为这个转换计时,但也许使用其他东西会更快。
我也对其他可能性持开放态度,这就是我想到的。
注意:拆分文件不是我想要探索的选项,因为我可能会将其部署在我不应该在其中创建自己的文件的服务器上,但如果它真的能提高性能,我可能会听.
其他说明:我是 java 线程的新手,也是 StackOverflow 的新手。温柔一点。
public class BigCount2 {
public static void main(String[] args) throws IOException, InterruptedException {
int num, counter;
long i, j;
String delimiterString = " ";
ArrayList<Character> delim = new ArrayList<Character>();
for (char c : delimiterString.toCharArray()) {
delim.add(c);
}
int counter2 = 0;
num = Integer.parseInt(args[0]);
int bytesToRead = 1024 * 1024 * 1024 / 2; //500 MB, size of loop
int remainder = bytesToRead % num;
int k = 0;
bytesToRead = bytesToRead - remainder;
int byr = bytesToRead / num;
String filepath = "C:/Users/Daniel/Desktop/int-dataset-10g.dat";
RandomAccessFile file = new RandomAccessFile(filepath, "r");
Thread[] t = new Thread [num];//array of threads
ConcurrentMap<Integer, Integer> wordCountMap = new ConcurrentHashMap<Integer, Integer>(25000);
byte [] byteArray = new byte [byr]; //allocates 500mb to a 2D byte array
char[] newbyte;
for (i = 0; i < file.length(); i += bytesToRead) {
counter = 0;
for (j = 0; j < bytesToRead; j += byr) {
file.seek(i + j);
file.read(byteArray, 0, byr);
newbyte = new String(byteArray).toCharArray();
t[counter] = new Thread(
new BigCountThread2(counter,
newbyte,
delim,
wordCountMap));//giving each thread t[i] different file fileReader[i]
t[counter].start();
counter++;
newbyte = null;
}
for (k = 0; k < num; k++){
t[k].join(); //main thread continues after ALL threads have finished.
}
counter2++;
System.gc();
}
file.close();
System.exit(0);
}
}
class BigCountThread2 implements Runnable {
private final ConcurrentMap<Integer, Integer> wordCountMap;
char [] newbyte;
private ArrayList<Character> delim;
private int threadId; //use for later
BigCountThread2(int tid,
char[] newbyte,
ArrayList<Character> delim,
ConcurrentMap<Integer, Integer> wordCountMap) {
this.delim = delim;
threadId = tid;
this.wordCountMap = wordCountMap;
this.newbyte = newbyte;
}
public void run() {
int intCheck = 0;
int counter = 0; int i = 0; Integer check; int j =0; int temp = 0; int intbuilder = 0;
for (i = 0; i < newbyte.length; i++) {
intCheck = Character.getNumericValue(newbyte[i]);
if (newbyte[i] == ' ' || intCheck == -1) { //once a delimiter is found, the current tempArray needs to be added to the MAP
check = wordCountMap.putIfAbsent(intbuilder, 1);
if (check != null) { //if returns null, then it is the first instance
wordCountMap.put(intbuilder, wordCountMap.get(intbuilder) + 1);
}
intbuilder = 0;
}
else {
intbuilder = (intbuilder * 10) + intCheck;
counter++;
}
}
}
}
最佳答案
关于大多数..的一些想法
.. I believe some sort of worker pool or executor service could solve this problem (I have not learned the syntax for this yet).
如果所有线程处理相同数量的数据所花费的时间大致相同,那么这里真的没有那么多“问题”。
然而,关于 Thread Pool 的一件好事它是否允许人们相当微不足道地调整一些基本参数,例如并发工作人员的数量。此外,使用 executor service Futures 可以提供额外的抽象级别;在这种情况下,如果每个线程都返回一个映射作为结果,会特别方便。
The program will only work for a file that contains integers. That's a problem. I struggled with this a lot, as I didn't know how to iterate through the data without creating loads of unused variables (using a String or even StringBuilder had awful performance) ..
这听起来像是一个实现问题。虽然我会先尝试 StreamTokenizer (因为它已经写好了),如果手动执行,我会 check out the source - 在简化“ token ”的概念时,可以省略其中的很多内容。 (它使用一个临时数组来构建 token 。)
I am using a global ConcurrentHashMap to story key value pairs. .. So is this the proper design? Would I gain in performance by giving each thread it's own hashmap, and then merging them all at the end?
每个线程使用单独的映射和合并策略会减少锁定并可能提高性能。此外,当前的实现损坏因为wordCountMap.put(intbuilder, wordCountMap.get(intbuilder) + 1)
不是原子的,因此操作可能会被计数。我会使用单独的映射,因为减少可变共享状态使线程程序更容易推理。
Is there any other way of seeking through a file with an offset without using the class RandomAccessMemory? This class will only read into a byte array, which I then have to convert. I haven't timed this conversion, but maybe it could be faster to use something else.
考虑在同一文件上每个线程 使用 FileReader(和 BufferedReader)。这将避免必须先将文件复制到数组中,然后将其切片用于各个线程,虽然总读取量相同,但可以避免吸收这么多内存。完成的读取实际上不是随机访问,而只是从不同偏移量开始的顺序(带有“跳过”)——每个线程仍然在互斥范围内工作。
另外,如果一个整数值被“切割”成两半,那么带有切片的原始代码被破坏,因为每个线程都会读取一半的字。一个解决方法是让每个线程跳过第一个单词 if 它是前一个 block 的延续(即更快扫描一个字节),然后根据需要读取它范围的末尾以完成最后一句话。
关于Java 字数 : a mediocre implementation,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/24133037/
我用 Java 实现了一个字数统计程序。基本上,该程序需要一个大文件(在我的测试中,我使用了一个仅包含数字的 10 GB 数据文件),并计算每个“单词”出现的次数 - 在这种情况下,一个数字(例如 2
我正在编写一个 JavaScript 游戏。这个游戏显然需要不断地渲染一个屏幕,使用 Canvas 时,该屏幕必须是一个 Uint8Array(width * height * 4) (由 Canva
我是一名优秀的程序员,十分优秀!