我正在尝试在Java中创建一个并行版本的素数分解,并且有一个工作程序。但是,程序非常慢 - 比我的顺序版慢得多。我明白这可能与线程优化和绝对数量的线程有关(我尝试使用ExecutorService,但我不认为我真的掌握了它)。谁可以指出优化这段代码的方法?
class HovedFaktorArbeider implements Runnable //Class for first step factorization
{
int fra;
int til;
int id;
List<Long> tempFaktorer; //Must be long since we'll stumble upon primes larger than int.MAX_VALUE accidentally
long[] lokaleFaktorer;
CyclicBarrier faktorBarrier = new CyclicBarrier(k+1);
ExecutorService executorService = Executors.newFixedThreadPool(2);
long g;
public HovedFaktorArbeider(int fra, int til, int id)
{
this.fra = fra;
this.til = til;
this.id = id;
}
public void run()
{
try
{
//int tempK = 2; //Erstatter bare k for aa sjekke
long tempN = (long) n;
g = (tempN*tempN)-100;
long tall = g + (long) fra; //The long numbers to be factorized
for(int i = fra; i <= til; i++) //For the number split
{
int tempFra = 0;
int tempTil = 0;
int rest = 0;
int faktor = 0;
if(primes.size() % k > 0) //If not perfect division
{
rest = (primes.size() % k); //Saving remainder
faktor = (primes.size()/k); //Saving divisor, spreading remainder
rest--; //Decrement remainder
}
else //If perfect divison
faktor = primes.size()/k;
tempTil = faktor; //Setting end value
tempFaktorer = new ArrayList<Long>();
for(int ii = 0; ii < k; ii++) //For the prime number split
{
//executorService.submit(new HjelpeFaktorArbeider(tempFra, tempTil, tall, ii));
new Thread(new HjelpeFaktorArbeider(tempFra, tempTil, tall, ii)).start();
tempFra = tempTil + 1; //Set new value for start
if(rest > 0)
{
tempTil += faktor + 1; //Spreading remainder
rest--;
}
else
tempTil += faktor; //New end value
}
faktorBarrier.await();
lokaleFaktorer = new long[tempFaktorer.size()];
for(int j = 0; j < tempFaktorer.size(); j++)
{
lokaleFaktorer[j] = tempFaktorer.get(j);
}
faktorer[i] = lokaleFaktorer; //TNB: i does not start at 0, so placement should be correct
tall++;
}
mainBarrier.await();
executorService.shutdown();
}
catch(Exception e){e.printStackTrace();}
}
public synchronized void oppdaterTempFaktorer(long tall)
{
tempFaktorer.add(tall);
}
class HjelpeFaktorArbeider implements Runnable //Class for second step factorization
{
int fra;
int til;
int id;
long tall;
public HjelpeFaktorArbeider(int fra, int til, long tall, int id)
{
this.fra = fra;
this.til = til;
this.id = id;
this.tall = tall;
}
public void run()
{
try
{
long t = tall;
for(int i = fra; i < til; i++)
{
int primtall = primes.get(i);
while(t % primtall == 0)
{
try
{
oppdaterTempFaktorer((long) primtall);
}
catch(Exception e){e.printStackTrace();}
t = t/primtall;
}
}
runBarrier.await();
if(t > 1 && id == 0 && !tempFaktorer.contains(t))
{
try
{
oppdaterTempFaktorer(t);
}
catch(Exception e){e.printStackTrace();}
}
faktorBarrier.await();
}
catch(Exception e){e.printStackTrace();}
}
}
}
截至目前,我有一份通过Erastothenes'Sieve找到的素数列表,一个限制n和核心k(我的机器上有8个)。
P.S。:有两个Runnable类的原因是我需要每个因子化由多个线程执行。
答案 0 :(得分:2)
如果您对并发感兴趣,我建议您查看其他并发模型,例如Futures
或Actors
。线程和锁是SOooo0o 2007。
关于如何更快地制作并行代码的问题,这是十亿美元的问题,有许多方法。它完全取决于您的问题和架构。
因此,从您的问题开始,使用并行体系结构并不是一个很棒的问题,因为例如说您有9个线程,并检查数字2,3,4,5,6,7 ,8,9,10,这已经非常糟糕,因为你不必检查4,6,8,9,10为2&amp; 3会告诉你那些非常糟糕的(好吧你可能不会检查偶数但只是为了证明我的观点)。因此,有些问题无法很好地使用并行代码,如您所见。
关于如何有效地并行化Java代码的问题,最受欢迎的答案是不这样做。如今程序员更关注的是不阻塞通常围绕don't call me we'll call you
主体的线程。但是如何为数学问题编写高效的并行代码是一个过于宽泛的计算机科学问题。
但总的来说,你的问题太宽泛了。