本文介绍了线程的所有主题有了固定的线程池和任务大数的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我用一个程序来运行考拉兹猜想( http://en.wikipedia.org/维基/ Collat​​z_conje​​cture )从数学。我实现了运行猜想算法(并且给你回的输出)和一个创建一个固定的线程池(我的处理器数量:8)的一类,并接受可赎回■哪些是呼吁猜想算法。

我创建了一个的HashSet<可赎回> 对于所有的数字之间1(输入类型必须为正整数)和40万。该挂起(貌似)永远,但较低的数字制定得很好,这很奇怪。陌生人然而,运行它似乎需要更长的时间比它需要一个单一的线程来处理的相同的信息量来处理这些呼叫;它也显著涨大的存储器。

有关例如,我的计算机上,该程序需要不到一秒,与400000(终值)执行算法(只有一个迭代)和所有的更低的值需要较少的时间来计算(或许除素数,这需要较长时间),我运行Windows 8.1有8GB的内存,以及8个逻辑处理器为2.2GHz。

code:

 私有静态无效initThreads()抛出InterruptedException的{
    //Files.createDirectories(SEQUENCER_FOLDER_PATH);
    //Files.createFile(SEQUENCER_FILE_PATH);
    ExecutorService的服务= Executors.newFixedThreadPool(8,新的ThreadFactory(){
        私人BigInteger的数量= BigInteger.ZERO;

        @覆盖
        公共主题newThread(Runnable的R){
            数= count.add(BigInteger.ONE);
            返回新的线程(R,在Collat​​z序主题:+计);
        }
    });
    INT finalNumber = 400_000;
    最后的HashSet<可赎回<太虚>>任务=新的HashSet<>(finalNumber);
    为(长L = 1; L< = finalNumber,L ++){
        最终的BigInteger数= BigInteger.valueOf(升);
        tasks.add(() - > {
            Collat​​zSequencer序=新Collat​​zSequencer(新的BigInteger(number.toString()));
            同步(数据集){
                dataSet.put(号码,sequencer.init());
            }
            返回null;
        });
    }
    service.invokeAll(任务);
    螺纹dataThread =新主题(() - > {
        而(真){
            同步(数据集){
                如果(dataSet.size()== finalNumber){
                    通信System.err.println(值:\ N);
                    为(Collat​​zSequencer.FinalSequencerReport数据:dataSet.values​​()){
                        通信System.err.println(项:+ data.getInitialValue()+,+ data.getIterations());
                    }
                    System.exit(0);
                }
            }
        }
    },考拉兹猜想数据集主题);
    dataThread.start();
}
 

考拉兹猜想算法:

  / *
 *要改变这种许可证标头,选择在项目属性许可头。
 *要改变这个模板文件,选择工具|模板
 *和打开在编辑器中的模板。
 * /
包com.collat​​zsequencer.core;

进口java.math.BigInteger的;

/ **
 *用于计算在Collat​​z序列定序。
 *
 * @author莎拉·绍博
 * @version 1.0
 * /
公共类Collat​​zSequencer {

私人最终BigInteger的初值;

公共Collat​​zSequencer(的BigInteger到currentValue){
    如果(到currentValue == NULL){
        抛出新的NullPointerException异常(传递不能为空值);
    }否则如果(currentValue.compareTo(新的BigInteger(1))≤; 0){
        抛出新NumberFormatException的(传递给构造函数的值必须是一个自然数。);
    }
    this.initialValue =到currentValue;
}

公共FinalSequencerReport的init(){
    返回新FinalSequencerReport(performOperation(新SequencerReport(this.initialValue)),this.initialValue);
}

私人SequencerReport performOperation(SequencerReport报告){
    如果(report.getResult()。等于(新的BigInteger(1))){
        返回新SequencerReport(report.getResult(),report.getIterations(),report.getSequence()长度()> 1。
                ? 。report.getSequence()子(0,report.getSequence()长度() -  3。)说:序列开始和结束于1<没有完成>);
    }否则如果(report.getResult()。模(新的BigInteger(2))。等于(新的BigInteger(0))){
        BigInteger值= report.getResult()分(新的BigInteger(2))。
        返回performOperation(新SequencerReport(值,report.getIterations()。添加(新的BigInteger(1)),
                report.getSequence()++ report.getResult()+/ 2  - >中+价值+ - >中));
    } 其他 {
        。BigInteger值= report.getResult()乘以(新的BigInteger(3))增加(新的BigInteger(1))。
        返回performOperation(新SequencerReport(值,report.getIterations()
                。新增(新的BigInteger(1)),report.getSequence()+ report.getResult()+* 3 + 1  - >中+价值+ - >中));
    }
}

公共静态final类FinalSequencerReport扩展SequencerReport {

    私人最终BigInteger的初值;
    私人最终字符串finalFormattedString;

    公共FinalSequencerReport(SequencerReport finalReport,BigInteger的初值){
        超级(finalReport.getResult(),finalReport.getIterations(),finalReport.getSequence());
        this.initialValue =初值;
        this.finalFormattedString =初始值:
                + getInitialValue()+\ nFinal值:+的getResult()+\ nIterations:
                + getIterations()+\ nAlgebraic序列:\ N+某个getSequence();
    }

    公共字符串getFinalFormattedString(){
        返回finalFormattedString;
    }

    公众的BigInteger getInitialValue(){
        返回初值;
    }
}

公共静态类SequencerReport {

    私人最终BigInteger的结果,迭代;
    私人最终字符串序列;

    公共SequencerReport(BigInteger的结果){
        这(结果是,新的BigInteger(0),);
    }

    公共SequencerReport(BigInteger的结果,BigInteger的迭代,串序列){
        this.result =结果;
        this.iterations =迭代;
        this.sequence =序列;
    }

    公众的BigInteger的getResult(){
        返回this.result;
    }

    公众的BigInteger getIterations(){
        返回this.iterations;
    }

    公共字符串某个getSequence(){
        返回this.sequence;
    }

  }
}
 

解决方案

正如你所说,你的code工作;这个问题可能只是性能。有些事情我会尝试:

  1. 使用,而不是的BigInteger 的。 的BigInteger 是很慢的。
  2. 而不是的MOD 2 (或%2 ),使用 &放大器; 1 。二进制,将有实际上是相同的结果,是要快得多。
  3. 您正在做的方式,方法太多了字符串操作。覆盖 sequencerReport.toString(),并让它做的toString 要求在所有当你打印的数据结束
  4. 请不要做新的ThreadFactory()。使用<一个href="http://docs.guava-libraries.google$c$c.com/git/javadoc/com/google/common/util/concurrent/ThreadFactoryBuilder.html"相对=nofollow>番石榴的ThreadFactoryBuilder 。
    • 您永远不应该叫新的Thread()曾经在code,除非你真的知道自己在做什么,这意味着不这样做。
  5. 添加,而不是一个繁忙的循环等待/通知机制 dataThread 。呼叫 dataSet.notify()当工作完成和 dataSet.wait() dataThread 的身体。

I'm using a program to run the Collatz Conjecture (http://en.wikipedia.org/wiki/Collatz_conjecture) from mathematics. I've implemented a class that runs the conjecture algorithm (and gives you back the output) and one that creates a fixed thread pool (with my number of processors: 8) and accepts Callables which are calls for the conjecture algorithm.

I created a HashSet<Callable> for all the numbers between 1 (the input type must be a positive integer) and 400,000. This hangs (seemingly) forever, but lower numbers work out just fine, which is strange. Stranger yet, running it appears to take longer to process these calls than it takes a single thread to process the same amount of information; it also bloats the memory significantly.

For instance, on my computer, the program takes less than a second to perform the algorithm (just one iteration) with 400,000 (the final value) and all the lower values take less time to compute (maybe with the exception of primes, which take longer) I'm running Windows 8.1 with 8GB ram, and 8 logical processors at 2.2Ghz.

Code:

private static void initThreads() throws InterruptedException {
    //Files.createDirectories(SEQUENCER_FOLDER_PATH);
    //Files.createFile(SEQUENCER_FILE_PATH);
    ExecutorService service = Executors.newFixedThreadPool(8, new ThreadFactory() {
        private BigInteger count = BigInteger.ZERO;

        @Override
        public Thread newThread(Runnable r) {
            count = count.add(BigInteger.ONE);
            return new Thread(r, "Collatz Sequencer Thread: " + count);
        }
    });
    int finalNumber = 400_000;
    final HashSet<Callable<Void>> tasks = new HashSet<>(finalNumber);
    for (long l = 1; l <= finalNumber; l++) {
        final BigInteger number = BigInteger.valueOf(l);
        tasks.add(() -> {
            CollatzSequencer sequencer = new CollatzSequencer(new BigInteger(number.toString()));
            synchronized (dataSet) {
                dataSet.put(number, sequencer.init());
            }
            return null;
        });
    }
    service.invokeAll(tasks);
    Thread dataThread = new Thread(() -> {
        while (true) {
            synchronized (dataSet) {
                if (dataSet.size() == finalNumber) {
                    System.err.println("Values: \n");
                    for (CollatzSequencer.FinalSequencerReport data : dataSet.values()) {
                        System.err.println("Entry: " + data.getInitialValue() + ", " + data.getIterations());
                    }
                    System.exit(0);
                }
            }
        }
    }, "Collatz Conjecture Data Set Thread");
    dataThread.start();
}

Collatz Conjecture Algorithm:

/*
 * To change this license header, choose License Headers in Project Properties.
 * To change this template file, choose Tools | Templates
 * and open the template in the editor.
 */
package com.collatzsequencer.core;

import java.math.BigInteger;

/**
 * A sequencer used for computing the collatz sequence.
 *
 * @author Sarah Szabo
 * @version 1.0
 */
public class CollatzSequencer {

private final BigInteger initialValue;

public CollatzSequencer(BigInteger currentValue) {
    if (currentValue == null) {
        throw new NullPointerException("Value passed can't be null");
    } else if (currentValue.compareTo(new BigInteger("1")) < 0) {
        throw new NumberFormatException("The value passed to the constructor must be a natural number.");
    }
    this.initialValue = currentValue;
}

public FinalSequencerReport init() {
    return new FinalSequencerReport(performOperation(new SequencerReport(this.initialValue)), this.initialValue);
}

private SequencerReport performOperation(SequencerReport report) {
    if (report.getResult().equals(new BigInteger("1"))) {
        return new SequencerReport(report.getResult(), report.getIterations(), report.getSequence().length() > 1
                ? report.getSequence().substring(0, report.getSequence().length() - 3) : "The sequence starts and ends at 1 <Nothing Done>");
    } else if (report.getResult().mod(new BigInteger("2")).equals(new BigInteger("0"))) {
        BigInteger value = report.getResult().divide(new BigInteger("2"));
        return performOperation(new SequencerReport(value, report.getIterations().add(new BigInteger("1")),
                report.getSequence() + " " + report.getResult() + "/2 -> " + value + " ->"));
    } else {
        BigInteger value = report.getResult().multiply(new BigInteger("3")).add(new BigInteger("1"));
        return performOperation(new SequencerReport(value, report.getIterations()
                .add(new BigInteger("1")), report.getSequence() + report.getResult() + " * 3 + 1 ->" + value + " ->"));
    }
}

public static final class FinalSequencerReport extends SequencerReport {

    private final BigInteger initialValue;
    private final String finalFormattedString;

    public FinalSequencerReport(SequencerReport finalReport, BigInteger initialValue) {
        super(finalReport.getResult(), finalReport.getIterations(), finalReport.getSequence());
        this.initialValue = initialValue;
        this.finalFormattedString = "Initial Value: "
                + getInitialValue() + "\nFinal Value: " + getResult() + "\nIterations:  "
                + getIterations() + "\nAlgebraic Sequence:\n" + getSequence();
    }

    public String getFinalFormattedString() {
        return finalFormattedString;
    }

    public BigInteger getInitialValue() {
        return initialValue;
    }
}

public static class SequencerReport {

    private final BigInteger result, iterations;
    private final String sequence;

    public SequencerReport(BigInteger result) {
        this(result, new BigInteger("0"), "");
    }

    public SequencerReport(BigInteger result, BigInteger iterations, String sequence) {
        this.result = result;
        this.iterations = iterations;
        this.sequence = sequence;
    }

    public BigInteger getResult() {
        return this.result;
    }

    public BigInteger getIterations() {
        return this.iterations;
    }

    public String getSequence() {
        return this.sequence;
    }

  }
}
解决方案

As you said, your code works; the problem is probably just performance. Some things I would try:

  1. Use long instead of BigInteger. BigInteger is very slow.
  2. Instead of mod 2 (or % 2), use & 1. The binary AND will have effectively the same result and is much faster.
  3. You are doing way, way too much String manipulation. Override sequencerReport.toString() and have it do the toString calls all at the end when you're printing the data.
  4. Don't do new ThreadFactory(). Use Guava's ThreadFactoryBuilder.
    • You should never call new Thread() ever in your code unless you really know what you're doing, which means don't do it.
  5. Add a wait/notify mechanism for dataThread instead of a busy loop. Call dataSet.notify() when the work is done and dataSet.wait() inside the dataThread body.

这篇关于线程的所有主题有了固定的线程池和任务大数的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!

09-05 15:28