在嵌套 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 频道。

停止程序有点棘手。我们需要一个停止例程来等待所有消费者或破解密码。