有可能让它 运行 更快吗?
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);
}
}
我已经尝试了所有方法,添加了一个特殊的 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);
}
}