有可能让它 运行 更快吗?

Is it possible to make it run any faster?

我已经尝试了所有方法,添加了一个特殊的 Parallel For 循环,但速度不够快。 有没有办法让它 运行 更快? 我知道也可以在 GPU 上进行这些计算,但我对此没有任何经验。

为了比较,这里是否充分发挥了 PC 规格:

CPU: AMD Ryzen 5 3400G with Radeon Vega Graphics 3.70 GHz

GPU: AMD Radeon rx580 8GB

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
using System.Timers;


    namespace MyProgram
    {
        public partial class Form1 : Form
        {
            public Form1()
            {
                InitializeComponent();
            } 
           
            int[] code;
            int time = 0;
            Char[] characters = new Char[] 
            {
                'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i','j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z',
                '0', '1', '2', '3', '4', '5', '6', '7', '8', '9' 
            };
    
            String passTry = "";       
    
            private void button1_Click(object sender, EventArgs e)
            {
                code = null;
                time = 0;
                passTry = "";
                code = new int[int.Parse(LengthBox.Text)];
                OutputBox.AppendText("Trying to break password...");
                OutputBox.AppendText(Environment.NewLine);
              
    
                Parallel.For(0, int.Parse(LengthBox.Text), i =>
                {
                    code[i] = 0;
                });
    
                timer1.Enabled = true;
    
               Task.Run(() =>
    
               {
    
                    while (passTry!=passOrig.Text)
                    {
                            Parallel.For(0, (code.Length-1), o =>
                            {
                                
                                if (code[o] > 34 && o < code.Length)
                                {
                                    code[o] = 0;
                                    code[o+1] += 1; 
                                }
    
                                passTry = "";
    
                                Parallel.For(0, (code.Length), i =>
                                {
                                    if (passTry.Length < code.Length)
                                    {
                                        passTry +=characters[code[i]];
                                    }
                                });
    
                           
                            });
    
                            code[0] = code[0] + 1;
                    }
               });
            }
        
          
    
    
            private void Form1_Load(object sender, EventArgs e)
            {
              
            }
    
            private void timer1_Tick(object sender, EventArgs e)
            {
                timeLbl.Text = (time/10).ToString() + "s";
                time++;
    
                if (passTry.Length == code.Length)
                {
                    OutputBox.AppendText("Trying password " + passTry + "...");
                    OutputBox.AppendText(Environment.NewLine);
    
                    if (passOrig.Text == passTry)
                    {
                        OutputBox.AppendText("Success, Password found " + passTry);
                        OutputBox.AppendText(Environment.NewLine);
                        timer1.Enabled = false;
                    }
                }
            }
        
        }
    }

我的代码采用了组合锁的简单暴力算法。从 0 0 0 0 开始。 然后在第一个数字上加一个,当数字达到最大值时重置它并在下一个数字上加一个,当下一个数字达到最大值时,一次又一次地向下一个数字添加一个,直到转换后的字符连接到字符串的结果不匹配字符串 passOrig.Text.

Combination lock+ conversion
    
    0 0 0 0 = A A A A
    1 0 0 0 = B A A A
    2 0 0 0 = C A A A 
    3 0 0 0 = D A A A
    0 1 0 0 = A B A A
    1 1 0 0 = B B A A
    2 1 0 0 = C B A A
    3 1 0 0 = D B A A
    0 2 0 0 = A C A A


//code to string conversion

Parallel.For(0, (code.Length), i =>
                            {
                                if (passTry.Length < code.Length)
                                {
                                    passTry +=characters[code[i]];
                                }
                            });

编辑:这只是部署后的第一部分,原始密码将不为人知。唯一已知的值是它是否是密码(真或假)thx 所有答案都有 2 个有趣的答案,但我认为我目前没有理解它们的脑容量。

我尽量不去想太多,写了这个单线程版本,在我的笔记本电脑上,它似乎比问题中显示的要快数百倍。

我用“zzzz”进行了测试,因为这是我实施的最坏情况。

我的版本需要 ~0.1 秒。

您的版本耗时超过 10 秒。

static void Naive(string password)
{
    var sw = Stopwatch.StartNew();
    var characters = new string(new Char[]
    {
        'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i','j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9' 
    });
    int characterLength = characters.Length;
    
    // Let's make the password an array of numbers
    byte[] passwordAsNumbers = password.Select(c =>(byte)characters.IndexOf(c)).ToArray();

    var attempt = new byte[password.Length];

    Find(0);
    var found = new string(attempt.Select(i => characters[i]).ToArray());
    var elapsed = sw.Elapsed;

    bool Find(int index)
    {
        if (index >= attempt.Length) return false;

        for (byte i = 0; i < characterLength; i++)
        {
            attempt[index] = i;
            if (attempt.SequenceEqual(passwordAsNumbers)) return true;
            if (Find(index + 1)) return true;
        }
        return false;
    }
}

好的,让我们假设当它上线时你会有这样的方法:

public bool IsItTheCombination(string combo) =>
  return combo=="FEDC"; //returns true if the input is FEDC

你说你想从 AAAA 开始,然后尝试 AAAB、AAAC、AAAD 等等。在 AAAJ -> AABA 之后,因为如果 A 是第 0 个字母,J 就是第 9 个字母。最终,在 7654 (FEDC) 猜测之后,您将击中正确的组合。您不知道 FEDC 实际上是什么。您只需用不同的字符串一遍又一遍地调用它并得到 true 或 false

所以这实际上就像计数,0000、0001、0002、..、0009、0010。除了我们使用字母字符 A 而不是数字字符 0。


让我们有一个从 0 到 9999 的循环 - 这就是所有组合

for(int x = 0; x <= 9999; x++){

}

现在我们只需要把0000变成AAAA就可以了。好在 C# 中的字符和数字是可以互换的

我们如何将一个整数分解成千位、百位、十位和单位?可以把它做成一根绳子,然后把它拉开。我们也可以用数学来做。我们来做数学吧。

  • 1234 除以 1 modulo 10 等于 4.
  • 1234 除以 10 modulo 10 等于 3 .
  • 1234 除以 100 modulo 10 是 2 .
  • 1234 除以 1000 modulo 10 是 1.

我们不需要除以 1,或者在除以 1000 之后 modulo(非操作)

for(int x = 0; x <= 9999; x++){

  int thousands = x/1000;
  int hundreds = (x/100)%10;
  int tens = (x/10)%10;
  int units = x%10;

}

所以当 x = 1234 时,我们现在有 4 个变量代表 4 个数字中的每一个。要将它们变成一个字符,您所要做的就是添加您想要的任何字符,并将其转换为一个字符:

charc c = (char)('A' + 0);

A+0是A.A+1是B.A+2是C..

for(int x = 0; x <= 9999; x++){

  char thousands = (char)('A' + x/1000);
  char hundreds = (char)('A' + (x/100)%10);
  char tens = (char)('A' + (x/10)%10);
  char units = (char)('A' + x%10);

}

您现在有 4 个字符。将字符转换为字符串很容易,如果这些字符在数组中则更容易,因为我们可以使用 new string(char[]) 构造函数

数组mode:

char[] guess = new char[4];
for(int x = 0; x <= 9999; x++){

  guess[0] = (char)('A' + x/1000);
  guess[1] = (char)('A' + (x/100)%10);
  guess[2] = (char)('A' + (x/10)%10);
  guess[3] = (char)('A' + x%10);

}

那就看看猜对了没有:

char[] guess = new char[4];
for(int x = 0; x <= 9999; x++){

  guess[0] = (char)('A' + x/1000);
  guess[1] = (char)('A' + (x/100)%10);
  guess[2] = (char)('A' + (x/10)%10);
  guess[3] = (char)('A' + x%10);

  var guessStr = new string(guess);
  if(IsItTheCombination(guessStr)){
    Console.WriteLine("The combo is " + guessStr);
  }
}

当然,这可以根据任何长度的猜测进行更改。向后计算也更容易,因为每次除以 10 就可以切掉另一个数字:

  guess[3] = (char)('A' + x%10);
  x=x/10;
  guess[2] = (char)('A' + x%10);
  x=x/10;
  guess[1] = (char)('A' + x%10);
  x=x/10;
  guess[0] = (char)('A' + x%10);

可以看到所有的操作都变得一样了:mod10,赋值,一遍又一遍地除10。这意味着内部循环可以处理我们的逻辑:

char[] guess = new char[20];
for(int x = (int)Math.Pow(10, guess.Length-1) - 1; x >= 0; x--){

  int num = x;                                   //take a copy of x because we'll modify it with division and we don't want to lose our place in the brute forcing

  
  guess[guess.Length - 1] = (char)('A' + x%10);  //do the right most digit as a special case (no division)
  for(int c = guess.Length - 2; c >= 0; c--){
    num = num/10;                                //cut a digit off
    guess[c] = (char)('A' + num%10);             //what is the rightmost digit?
  }

  var guessStr = new string(guess);
  if(IsItTheCombination(guessStr)){
    Console.WriteLine("The combo is " + guessStr);
  }
}