【问题标题】:How to periodically print to terminal from an if statement that is nested in a while loop (Java)如何从嵌套在while循环中的if语句定期打印到终端(Java)
【发布时间】:2019-04-07 02:13:01
【问题描述】:

我正在编写一个 java 应用程序,它将重复地散列一系列输入值,直到满足条件。我通过在 while 循环中嵌套一系列 if/else 语句来实现这一点。我希望能够在应用程序主动散列时每 3 秒将散列率打印到终端,并且在满足条件之前不要重复。我曾尝试使用 ExecutorService 并安排 TimerTask ,但两者都没有按照我希望的方式工作,因为在满足应该停止它们的条件后它们都继续执行。我知道我错过了一些东西,但我不知道是什么):

我已经包含了一个小sn-p,请随时询问您可能认为相关的任何信息。

任何帮助将不胜感激!

我尝试使用这样的 TimerTask:

while(iterator) {
    if (difficulty == 1) {
        if (!hash.startsWith("0")) {
            long updatedTime = System.nanoTime();
            Nonce++;
            long deltaN = updatedTime - startTime;
            long deltaS = (deltaN / 1000000000);
            long hashRate = (Nonce / deltaS);
            Timer timer = new Timer();
            timer.schedule(new TimerTask() {
                @Override
                public void run() {
                    System.out.println("Current hash rate: " + hashRate + " " + "hash/s");
                }
            }, 0, 3000);
        } else {
              System.out.println("Valid hash found! " + hash);
              iterator = false;
        }
    }
}  

编辑:完成后的内容本质上是一个俗气的“区块链”,我将用作说明目的作为教学工具,考虑到这一点,我在下面包含了“矿工”方法的其余部分:

public void miner(long index, long currentTimeMillis, long data, long Nonce, String previousBlockHash, int difficulty) throws InterruptedException {
        this.index = index;
        this.currentTimeMillis = currentTimeMillis;
        this.pszTimeStamp = pszTimeStamp;
        this.Nonce = Nonce;
        this.previousBlockHash = previousBlockHash;
        this.difficulty = difficulty;
        this.data = data;
        boolean iterator = true;
        String blockHeader = (index + currentTimeMillis + data + Nonce + previousBlockHash + difficulty);
        String hash = SHA256.generateHash(blockHeader);
        long startTime = System.nanoTime();
        TimeUnit.SECONDS.sleep(2);

        while (iterator) {
            blockHeader = (index + currentTimeMillis + data + Nonce + previousBlockHash + difficulty);
            hash = SHA256.generateHash(blockHeader);
            if (difficulty == 1) {
                if (!hash.startsWith("0")) {
                    long updatedTime = System.nanoTime();
                    Nonce++;
                    long deltaN = updatedTime - startTime;
                    long deltaS = (deltaN / 1000000000);
                    long hashRate = (Nonce / deltaS);
                    System.out.println("Current hash rate: " + hashRate
                } else {
                    System.out.println("\n");
                    System.out.println("Hash found! \n");
                    System.out.println("Mined block hash: \n" + hash);
                }
            } else if (difficulty == 2) {

            ...........

“miner”方法采用的所有参数都由包含主函数的启动类传递给它。我的目标是能够在每隔几秒搜索一次“有效”哈希时打印哈希率,而不是每秒打印数千次。

【问题讨论】:

    标签: java if-statement while-loop


    【解决方案1】:

    我有几点建议:

    • 我个人更喜欢在while(true) 循环中使用break 而不是循环变量。我觉得它使代码更具可读性;

    • 您正在循环内重新声明Timer,这意味着每次循环迭代都会创建一个新计时器。您需要在循环外创建一次计时器。

    Timer 变量必须是 final 才能让您在 TimerTask 的 run 函数中调用 timer.cancel()。如果您计划在 run 函数之外终止计时器,则 Timer 变量不必是 final 的。

    import java.util.*;
    
    public class Test{
        static double Nonce;
    
        public static void main(String... args) throws Exception{
            final Timer timer = new Timer();
            timer.schedule(new TimerTask(){
                public void run(){
                    //calcualte hashRate by any formula
                    double hashRate = Nonce/100.0;
    
                    //check if the timer needs to continue, else call timer.cancel()
    
                    System.out.println(hashRate);
                }
            }, 0, 500);
    
            while(true){
                Thread.sleep(100);
                Nonce++;
    
                if(Nonce == 100){
                    timer.cancel(); //or terminate the timer outside the loop
                    break;
                }
            }  
        }
    }
    

    如果您需要任何帮助,请告诉我。


    编辑:

    我注意到的一些事情:

    • 类变量Nonce不能是静态的,否则会在类的所有实例之间共享。

    • 函数声明中变量名不能为Nonce,否则在矿工函数中使用Nonce时会使用本地副本。

    • 如果不直接计算 hashRate,则 deltaS 可能为零,这可能导致除以 0 错误。

    如果您需要任何说明,请告诉我。

    public class ChainBuilder extends MainChain {
    
        private long index;
        private long currentTimeMillis;
        private long data;
        private int difficulty;
        private String pszTimeStamp;
        private String previousBlockHash;
        private String currentHash;
        private String genesisHash;
    
        public long Nonce; //Nonce cannot be be static, otherwise it will cause issues if more than one object is created.
        public static long startTime;
    
    .......
    public void miner(long index, long currentTimeMillis, long data, long _Nonce /*You cannot use Nonce here*/, String previousBlockHash, int difficulty) throws InterruptedException {
            this.index = index;
            this.currentTimeMillis = currentTimeMillis;
            this.pszTimeStamp = pszTimeStamp;
            this.Nonce = _Nonce; /*In this scope, Nonce refers to the local variable, and this.Nonce refers to the class variable. 
                                If you use Nonce in this scope, then the class variable will not be changed.*/
            this.previousBlockHash = previousBlockHash;
            this.difficulty = difficulty;
            this.data = data;
            boolean iterator = true;
            String blockHeader = (index + currentTimeMillis + data + Nonce + previousBlockHash + difficulty);
            String hash = SHA256.generateHash(blockHeader);
            startTime = System.nanoTime();
            TimeUnit.SECONDS.sleep(2);
    
            Timer timer = new Timer();
            timer.schedule(new TimerTask() {
                @Override
                public void run() {
                    long endTime = System.nanoTime();
                    long deltaN = endTime - startTime;
                    //long deltaS = (deltaN / 1_000_000_000);
                    long hashRate = (1_000_000_000 * Nonce / deltaN); /*calculate the hashRate directly, because if deltaN < 1_000_000_000, 
                                                                    then deltaS will be 0, giving a divide by zero error.*/
                    System.out.println("Current hash rate: " + hashRate + " " + "hash/s");
                }
            }, 0, 3000);
            while (iterator) {
                blockHeader = (index + currentTimeMillis + data + Nonce + previousBlockHash + difficulty);
                hash = SHA256.generateHash(blockHeader);
                if (difficulty == 1) {
    
                    if (!hash.startsWith("0")) {
                        Nonce++;
                    } else {
                        System.out.println("Hash found!");
                        timer.cancel();
    .......
    

    【讨论】:

    • 感谢您的建议,但不幸的是,这并不能解决我的问题。哈希率正在计算,而不是递增。 nonce 值是用于创建散列的值之一,并且是唯一递增的值。完成后这将是一个俗气的“区块链”,我将用作说明目的作为教学工具。我将更新我的帖子以包含更多的方法,这样也许它会更有意义正在发生的事情和我想要实现的目标。
    • 我已经更新了代码。请让我知道这是否是您需要的。您可以让hashRate 成为全局(类)变量,并让所有 if 语句更新它,然后在需要时打印出hashRate。 @apt-getschwifty
    • 我们不能使用 nonce 值打破循环,因为它每次都会不同。它从 0 开始并递增,直到找到以正确数量的零开头的散列,这有时需要数百万甚至数十亿次迭代。不过,感谢您花时间看一看。这应该是一个简单的任务,它把我逼疯了,我无法弄清楚哈哈。
    • 我仅将 Nonce 值作为示例。有一些条件在满足时会导致循环终止。每次终止循环时只需调用timer.cancel(),计时器将停止打印到屏幕。
    • 不客气?。此外,只要您只使用对象的一个​​实例,声明Nonce static 不会导致任何错误,但我强烈建议您对此进行调查,因为它可能会导致一些非常非常难以确定的错误。我曾经不得不重写整个模块,因为我不小心声明了一个静态变量。
    【解决方案2】:

    好的,所以对我有用的是将相关变量声明为静态,将计时器的开始放在循环之前,并在发现有效哈希时取消,如下所示:

    public class ChainBuilder extends MainChain {
    
        private long index;
        private long currentTimeMillis;
        private long data;
        private int difficulty;
        private String pszTimeStamp;
        private String previousBlockHash;
        private String currentHash;
        private String genesisHash;
        public static long deltaS;
        public static long deltaN;
        public static long Nonce;
        public static long startTime;
        public static long endTime;
        public static long hashRate;
    .......
    public void miner(long index, long currentTimeMillis, long data, long Nonce, String previousBlockHash, int difficulty) throws InterruptedException {
            this.index = index;
            this.currentTimeMillis = currentTimeMillis;
            this.pszTimeStamp = pszTimeStamp;
            this.Nonce = Nonce;
            this.previousBlockHash = previousBlockHash;
            this.difficulty = difficulty;
            this.data = data;
            boolean iterator = true;
            String blockHeader = (index + currentTimeMillis + data + Nonce + previousBlockHash + difficulty);
            String hash = SHA256.generateHash(blockHeader);
            startTime = System.nanoTime();
            TimeUnit.SECONDS.sleep(2);
    
            Timer timer = new Timer();
            timer.schedule(new TimerTask() {
                @Override
                public void run() {
                    System.out.println("Current hash rate: " + hashRate + " " + "hash/s");
                }
            }, 0, 3000);
            while (iterator) {
                blockHeader = (index + currentTimeMillis + data + Nonce + previousBlockHash + difficulty);
                hash = SHA256.generateHash(blockHeader);
                if (difficulty == 1) {
    
                    if (!hash.startsWith("0")) {
                        endTime = System.nanoTime();
                        Nonce++;
                        deltaN = endTime - startTime;
                        deltaS = (deltaN / 1000000000);
                        hashRate = (Nonce / deltaS);
                    } else {
                        System.out.println("Hash found!");
                        timer.cancel();
    .......
    

    【讨论】: