在嵌套 for 循环中使用并发? (蛮力)
Using concurrency in nested for loop? (Brute force)
我正在改编我在 class 中编写的 C 程序的代码,并且我正在尝试将我用 C 编写的所有程序转换为 Go 以学习这门语言。不过,我还不完全 "getting" 并发。我如何将并发应用于嵌套的 for 循环?我程序的当前迭代很慢,比我用 C 编写的要慢得多。
这是我的代码:
package main
import (
"fmt"
"os"
"unsafe"
)
// #cgo LDFLAGS: -lcrypt
// #define _GNU_SOURCE
// #include <crypt.h>
// #include <stdlib.h>
import "C"
// credit for this solution goes to
// for showing that you can wrap go in C via CGO
// crypt wraps C library crypt_r
func crypt(key, salt string) string {
data := C.struct_crypt_data{}
ckey := C.CString(key)
csalt := C.CString(salt)
out := C.GoString(C.crypt_r(ckey, csalt, &data))
C.free(unsafe.Pointer(ckey))
C.free(unsafe.Pointer(csalt))
return out
}
func main() {
if len(os.Args) != 2 {
fmt.Println("Usage: ./cracker k")
return
}
cipher := os.Args[1]
var guess [5]byte
for i := 65; i < 123; i++ {
if i >= 91 && i <= 96 {
} else {
guess[0] = byte(i)
if cipher == crypt(string(guess[:1]), "50") {
fmt.Println(string(guess[:1]))
return
}
fmt.Println(string(guess[:1]))
for j := 65; j < 123; j++ {
if j >= 91 && j <= 96 {
} else {
guess[1] = byte(j)
if cipher == crypt(string(guess[:2]), "50") {
fmt.Println(string(guess[:2]))
return
}
fmt.Println(string(guess[:2]))
for k := 65; k < 123; k++ {
if k >= 91 && k <= 96 {
} else {
guess[2] = byte(k)
if cipher == crypt(string(guess[:3]), "50") {
fmt.Println(string(guess[:3]))
return
}
fmt.Println(string(guess[:3]))
for l := 65; l < 123; l++ {
if l >= 91 && l <= 96 {
} else {
guess[3] = byte(l)
if cipher == crypt(string(guess[:4]), "50") {
fmt.Println(string(guess[:4]))
return
}
fmt.Println(string(guess[:4]))
for m := 65; m < 123; m++ {
if m >= 91 && m <= 96 {
} else {
guess[4] = byte(m)
if cipher == crypt(string(guess[:5]), "50") {
fmt.Println(string(guess[:5]))
return
}
fmt.Println(string(guess[:5]))
}
}
}
}
}
}
}
}
}
}
}
该程序的目的是暴力破解 DES 哈希,它可以处理长度不超过 5 个字符的任何密码(因此,5 个嵌套 for 循环)。
我不会重写你的代码,但我可以给你一个示例解决方案,这样你就可以填空。
package main
import (
"fmt"
"runtime"
"sync"
)
func produce(in chan string) {
defer close(in)
for i := 0; i < 1000; i++ {
in <- fmt.Sprintf("%d", i)
}
}
func consume(in, out chan string, wg *sync.WaitGroup) {
defer wg.Done()
for s := range in {
if s == "500" {
out <- s
}
}
}
func stop(out chan string, wg *sync.WaitGroup) {
wg.Wait()
close(out)
}
func main() {
in, out := make(chan string), make(chan string)
wg := &sync.WaitGroup{}
go produce(in)
for i := 0; i < runtime.NumCPU(); i++ {
wg.Add(1)
go consume(in, out, wg)
}
go stop(out, wg)
fmt.Println(<-out)
}
这个想法是在生产者中产生密码建议,并将繁重的计算推给消费者。将有与 CPU 一样多的消费者。生产者通过关闭 in
频道来表示工作结束。消费者从 in
通道中获取下一个密码建议并尝试计算哈希值。如果他们成功了,他们会将密码放入 out
频道。
停止程序有点棘手。我们需要一个停止例程来等待所有消费者或破解密码。
我正在改编我在 class 中编写的 C 程序的代码,并且我正在尝试将我用 C 编写的所有程序转换为 Go 以学习这门语言。不过,我还不完全 "getting" 并发。我如何将并发应用于嵌套的 for 循环?我程序的当前迭代很慢,比我用 C 编写的要慢得多。
这是我的代码:
package main
import (
"fmt"
"os"
"unsafe"
)
// #cgo LDFLAGS: -lcrypt
// #define _GNU_SOURCE
// #include <crypt.h>
// #include <stdlib.h>
import "C"
// credit for this solution goes to
// for showing that you can wrap go in C via CGO
// crypt wraps C library crypt_r
func crypt(key, salt string) string {
data := C.struct_crypt_data{}
ckey := C.CString(key)
csalt := C.CString(salt)
out := C.GoString(C.crypt_r(ckey, csalt, &data))
C.free(unsafe.Pointer(ckey))
C.free(unsafe.Pointer(csalt))
return out
}
func main() {
if len(os.Args) != 2 {
fmt.Println("Usage: ./cracker k")
return
}
cipher := os.Args[1]
var guess [5]byte
for i := 65; i < 123; i++ {
if i >= 91 && i <= 96 {
} else {
guess[0] = byte(i)
if cipher == crypt(string(guess[:1]), "50") {
fmt.Println(string(guess[:1]))
return
}
fmt.Println(string(guess[:1]))
for j := 65; j < 123; j++ {
if j >= 91 && j <= 96 {
} else {
guess[1] = byte(j)
if cipher == crypt(string(guess[:2]), "50") {
fmt.Println(string(guess[:2]))
return
}
fmt.Println(string(guess[:2]))
for k := 65; k < 123; k++ {
if k >= 91 && k <= 96 {
} else {
guess[2] = byte(k)
if cipher == crypt(string(guess[:3]), "50") {
fmt.Println(string(guess[:3]))
return
}
fmt.Println(string(guess[:3]))
for l := 65; l < 123; l++ {
if l >= 91 && l <= 96 {
} else {
guess[3] = byte(l)
if cipher == crypt(string(guess[:4]), "50") {
fmt.Println(string(guess[:4]))
return
}
fmt.Println(string(guess[:4]))
for m := 65; m < 123; m++ {
if m >= 91 && m <= 96 {
} else {
guess[4] = byte(m)
if cipher == crypt(string(guess[:5]), "50") {
fmt.Println(string(guess[:5]))
return
}
fmt.Println(string(guess[:5]))
}
}
}
}
}
}
}
}
}
}
}
该程序的目的是暴力破解 DES 哈希,它可以处理长度不超过 5 个字符的任何密码(因此,5 个嵌套 for 循环)。
我不会重写你的代码,但我可以给你一个示例解决方案,这样你就可以填空。
package main
import (
"fmt"
"runtime"
"sync"
)
func produce(in chan string) {
defer close(in)
for i := 0; i < 1000; i++ {
in <- fmt.Sprintf("%d", i)
}
}
func consume(in, out chan string, wg *sync.WaitGroup) {
defer wg.Done()
for s := range in {
if s == "500" {
out <- s
}
}
}
func stop(out chan string, wg *sync.WaitGroup) {
wg.Wait()
close(out)
}
func main() {
in, out := make(chan string), make(chan string)
wg := &sync.WaitGroup{}
go produce(in)
for i := 0; i < runtime.NumCPU(); i++ {
wg.Add(1)
go consume(in, out, wg)
}
go stop(out, wg)
fmt.Println(<-out)
}
这个想法是在生产者中产生密码建议,并将繁重的计算推给消费者。将有与 CPU 一样多的消费者。生产者通过关闭 in
频道来表示工作结束。消费者从 in
通道中获取下一个密码建议并尝试计算哈希值。如果他们成功了,他们会将密码放入 out
频道。
停止程序有点棘手。我们需要一个停止例程来等待所有消费者或破解密码。