我正在接收一个包含约60,000行点坐标的文本文件(我希望尽快扩展)并执行从每个点到每个其他点的Mahalanobis距离,并将结果输出为文本文件。这意味着我的结果将近3,600,000,000行。我的程序每1或2秒创建大约60,000行。
我认为我的代码无法多线程吗?有没有更好的方法来编码这个算法?人们如何处理这些流程?
import java.io.BufferedWriter;
import java.io.File;
import java.io.FileWriter;
import java.io.IOException;
import java.io.PrintWriter;
import java.util.ArrayList;
import java.util.List;
import java.util.Scanner;
public class Coord {
public int a,b,c,d,e,f;
public static void main(String[] args) throws IOException {
PrintWriter out = new PrintWriter(new BufferedWriter(new FileWriter("/Users/evanlivingston/2a.txt", true)));
Scanner sc = new Scanner(new File("/Users/evanlivingston/1.txt"));
List<Coord> coords = new ArrayList<Coord>();{
// for each line in the file
while(sc.hasNextLine()) {
String[] numstrs = sc.nextLine().split("\\s+");
Coord c = new Coord();
c.a = Integer.parseInt(numstrs[1]);
c.b = Integer.parseInt(numstrs[2]);
c.c = Integer.parseInt(numstrs[3]);
c.d = Integer.parseInt(numstrs[4]);
c.e = Integer.parseInt(numstrs[5]);
c.f = Integer.parseInt(numstrs[6]);
coords.add(c);
}
// now you have all coords in memory
int counter = 0; {
for(int i=0; i<coords.size(); i++ )
for( int j=0; j<coords.size(); j++, counter++ )
{
Coord c1 = coords.get(i);
Coord c2 = coords.get(j);
double foo = ((c1.a - c2.a) * (c1.a - c2.a)) *1 ;
double goo = ((c1.b - c2.b) * (c1.b - c2.b)) *1 ;
double hoo = ((c1.c - c2.c) * (c1.c - c2.c)) *2 ;
double joo = ((c1.d - c2.d) * (c1.d - c2.d)) *2 ;
double koo = ((c1.e - c2.e) * (c1.e - c2.e)) *4 ;
double loo = ((c1.f - c2.f) * (c1.f - c2.f)) *4 ;
double zoo = Math.sqrt(foo + goo + hoo + joo + koo + loo);
out.println(counter + "; " + i + " " + j + " " + zoo);
System.out.println(counter + "; " + i + " " + j + " " + zoo);
}
out.flush();
out.close();
}
}
}
}
我的输入文件类似于
0 0 0 0 0 0 0
1 0 0 0 0 0 1
....
59318 12 2 12 2 12 2
第一个号码是占位符。这是所有替换组合的列表,仅限于您在最后一行中看到的金额。
现在看起来似乎计算需要大约16个小时,但这似乎仍然太长。更不用说我估计最终的文本输出大约是120 GB。答案 0 :(得分:7)
您的代码非常效率低下。您在文件中的每一行(!!!)上第二次重新读取该文件。磁盘IO非常慢。
你应该做的是将文件加载到已解析的内存结构(双精度数组)中,然后对其执行嵌套循环。
我认为我的代码是正确的 不能多线程?
你错了。这项任务将从线程中受益匪浅。但你的首要任务是摆脱重复的IO。我猜想性能会好得多。
更新到更新
将您的类重写为多个线程(默认为4)。下行:输出文件中的行不按顺序写入,但是如果需要,可以使用unix排序实用程序对计算后的行进行排序。仍然计算A-> B和B-> A,因为我无法想出一种简单的方法来存储A-> B的结果,而不是使用Java 64bit并安装一些64G的RAM。
import java.io.BufferedWriter;
import java.io.File;
import java.io.FileWriter;
import java.io.IOException;
import java.io.PrintWriter;
import java.io.Writer;
import java.util.ArrayList;
import java.util.List;
import java.util.Scanner;
public class Coord {
public int a, b, c, d, e, f;
private static class CoordsThread extends Thread {
private int start;
private int end;
private List<Coord> coords;
private PrintWriter out;
public CoordsThread(int start, int end, List<Coord> list, PrintWriter out) {
this.start = start;
this.end = end;
this.coords = list;
this.out = out;
// last block can be shorter
if( this.end > this.coords.size() ) this.end = this.coords.size();
}
public void run() {
System.out.println("started thread "+getName()+" for ["+start+";"+end+")");
for (int i = start; i < end; i++) {
for (int j = 0; j < coords.size(); j++ ) {
Coord c1 = coords.get(i);
Coord c2 = coords.get(j);
double foo = ((c1.a - c2.a) * (c1.a - c2.a)) * 1;
double goo = ((c1.b - c2.b) * (c1.b - c2.b)) * 1;
double hoo = ((c1.c - c2.c) * (c1.c - c2.c)) * 2;
double joo = ((c1.d - c2.d) * (c1.d - c2.d)) * 2;
double koo = ((c1.e - c2.e) * (c1.e - c2.e)) * 4;
double loo = ((c1.f - c2.f) * (c1.f - c2.f)) * 4;
double zoo = Math.sqrt(foo + goo + hoo + joo + koo + loo);
synchronized (out) {
out.println(i*coords.size()+j + "; " + i + " " + j + " " + zoo);
}
}
}
System.out.println("completed thread "+getName());
}
}
public static void main(String[] args) throws Exception {
PrintWriter out = new PrintWriter(new BufferedWriter(new FileWriter("2.txt")));
Scanner sc = new Scanner(new File("1.txt"));
List<Coord> coords = new ArrayList<Coord>();
// for each line in the file
while (sc.hasNextLine()) {
String[] numstrs = sc.nextLine().split("\\s+");
Coord c = new Coord();
c.a = Integer.parseInt(numstrs[1]);
c.b = Integer.parseInt(numstrs[2]);
c.c = Integer.parseInt(numstrs[3]);
c.d = Integer.parseInt(numstrs[4]);
c.e = Integer.parseInt(numstrs[5]);
c.f = Integer.parseInt(numstrs[6]);
coords.add(c);
}
System.out.println("total lines read: "+coords.size());
int threadsCount = 4;
List<Thread> ths = new ArrayList<Thread>();
int blockSize = coords.size()/threadsCount+1;
for( int i=0; i<threadsCount; ++i ) {
CoordsThread ct = new CoordsThread(i*blockSize, (i+1)*blockSize, coords, out);
ct.setName("Block"+i);
ths.add(ct);
}
for (Thread th : ths) {
th.start();
}
for (Thread th : ths) {
th.join();
}
out.flush();
out.close();
}
}
答案 1 :(得分:1)
您正在进行大量重复IO,非常昂贵,比您正在进行的任何计算都要高出几个数量级。
此外,您的问题域非常适合地图/减少场景,这不仅易于多线程,而且您应该能够在多台计算机上分配计算。
答案 2 :(得分:1)
您正在阅读文件1.txt
太多次。阅读一次,将其存储在int[][]
类型的数组中。
另外,请尝试增加BufferedWriter
实例的大小。
此外,让Scanner
实例在BufferedInputstream
上使用正确的字符集。