4

我确定我做错了什么,我有一个 Go 程序,它解析 OBJ 格式的 3D 模型并输出一个 json 对象。当我在不添加 goroutine 的情况下运行它时,我得到以下输出:

$ go run objParser.go ak47.obj extincteur_obj.obj 
--Creating ak47.json3d from ak47.obj
--Exported 85772 faces with 89088 verticies
--Creating extincteur_obj.json3d from extincteur_obj.obj
--Exported 150316 faces with 151425 verticies
Parsed 2 files in 8.4963s

然后我添加了 goroutines,我得到了这个输出:

$ go run objParser.go ak47.obj extincteur_obj.obj 
--Creating ak47.json3d from ak47.obj
--Creating extincteur_obj.json3d from extincteur_obj.obj
--Exported 85772 faces with 89088 verticies
--Exported 150316 faces with 151425 verticies
Parsed 2 files in 10.23137s

考虑到解析的交错,它的打印顺序是我所期望的,但我不知道为什么它实际上需要更长的时间!代码很长,我剪掉了我能做的,但它仍然很长,对此感到抱歉!

package main

func parseFile(name string, finished chan int) {
    var Verts []*Vertex
    var Texs []*TexCoord
    var Faces []*Face

    var objFile, mtlFile, jsonFile *os.File
    var parseMaterial bool

    // Set up files and i/o
    inName := name
    outName := strings.Replace(inName, ".obj", ".json3d", -1)
    parseMaterial = false

    fmt.Printf("--"+FgGreen+"Creating"+Reset+" %s from %s\n", outName, inName)

    var err error
    var part []byte
    var prefix bool

    if objFile, err = os.Open(inName); err != nil {
        fmt.Println(FgRed+"!!Failed to open input file!!"+Reset)
        return
    }

    if jsonFile, err = os.Create(outName); err != nil {
        fmt.Println(FgRed+"!!Failed to create output file!!"+Reset)
        return
    }

    reader := bufio.NewReader(objFile)
    writer := bufio.NewWriter(jsonFile)
    buffer := bytes.NewBuffer(make([]byte, 1024))

    // Read the file in and parse out what we need
    for {
        if part, prefix, err = reader.ReadLine(); err != nil {
            break
        }

        buffer.Write(part)
        if !prefix {
            line := buffer.String()
            if(strings.Contains(line, "v ")) {
                Verts = append(Verts, parseVertex(line))
            } else if(strings.Contains(line, "vt ")) {
                Texs = append(Texs, parseTexCoord(line))
            } else if(strings.Contains(line, "f ")) {
                Faces = append(Faces, parseFace(line, Verts, Texs))
            } else if(strings.Contains(line, "mtllib ")) {
                mtlName := strings.Split(line, " ")[1]
                if mtlFile, err = os.Open(mtlName); err != nil {
                    fmt.Printf("--"+FgRed+"Failed to find material file: %s\n"+Reset, mtlName)
                    parseMaterial = false
                } else {
                    parseMaterial = true
                }
            }
            buffer.Reset()
        }
    }

    if err == io.EOF {
        err = nil
    }

    objFile.Close()

    // Write out the data
    writer.WriteString("{\"obj\":[\n");

    // Write out the verts
    writer.WriteString("{\"vrt\":[\n");
    for i, vert := range Verts {
        writer.WriteString(vert.String())
        if i < len(Verts) - 1 { writer.WriteString(",") }
        writer.WriteString("\n")
    }

    // Write out the faces
    writer.WriteString("],\"fac\":[\n")
    for i, face := range Faces {
        writer.WriteString(face.String(true))
        if i < len(Faces) - 1 { writer.WriteString(",") }
        writer.WriteString("\n")
    }

    // Write out the normals
    writer.WriteString("],\"nrm\":[")
    for i, face := range Faces {


        writer.WriteString("[")
        for j, vert := range face.verts {
            length := math.Sqrt((vert.X * vert.X) + (vert.Y * vert.Y) + (vert.Z * vert.Z))
            x := vert.X / length
            y := vert.Y / length
            z := vert.Z / length
            normal := fmt.Sprintf("[%f,%f,%f]", x, y, z)
            writer.WriteString(normal)
            if(j < len(face.verts)-1) { writer.WriteString(",") }
        }
        writer.WriteString("]")




        //writer.WriteString("[0, 1, 0]")
        if i < len(Faces) - 1 { writer.WriteString(",") }
        writer.WriteString("\n")
    }

    // Write out the tex coords
    writer.WriteString("],\"tex\":[")
    for i, face := range Faces {
        writer.WriteString("[")
        writer.WriteString(face.tex[0].String())
        writer.WriteString(",")
        writer.WriteString(face.tex[1].String())
        writer.WriteString(",")
        writer.WriteString(face.tex[2].String())
        writer.WriteString("]")
        if i < len(Faces) - 1 { writer.WriteString(",") }
        writer.WriteString("\n")
    }

    // Close obj block
    writer.WriteString("]}]");

    if parseMaterial {
        writer.WriteString(",mat:[{");
        reader := bufio.NewReader(mtlFile)

        // Read the file in and parse out what we need
        for {
            if part, prefix, err = reader.ReadLine(); err != nil {
                break
            }

            buffer.Write(part)
            if !prefix {
                line := buffer.String()
                if(strings.Contains(line, "map_Kd ")) {
                    parts := strings.Split(line, " ")
                    entry := fmt.Sprintf("\"t\":\"%s\",", parts[1])
                    writer.WriteString(entry)

                    width, height := 256, 256
                    var imageFile *os.File
                    if imageFile, err = os.Open(parts[1]); err != nil {
                        fmt.Printf("--"+FgRed+"Failed to find %s, defaulting to 256x256"+Reset+"\n", parts[1])
                        return
                    } else {
                        var config image.Config
                        imageReader := bufio.NewReader(imageFile)
                        config, err = jpeg.DecodeConfig(imageReader)
                        width, height = config.Width, config.Height
                        fmt.Printf("--"+FgGreen+"Verifing"+Reset+" that %s is %dpx x %dpx\n", parts[1], width, height)
                    }

                    size := fmt.Sprintf("\"w\":%d,\"h\":%d,", width, height)
                    writer.WriteString(size)

                } else if(strings.Contains(line, "Kd ")) {
                    parts := strings.Split(line, " ")
                    entry := fmt.Sprintf("\"r\":%s, \"g\":%s, \"b\":%s,", parts[1], parts[2], parts[3])
                    writer.WriteString(entry)
                }
                buffer.Reset()
            }
        }

        if err == io.EOF {
            err = nil
        }

        writer.WriteString("\"res\":100,\"uv\":true}]");
    }

    // Close json
    writer.WriteString("}");
    writer.Flush()
    jsonFile.Close()

    fmt.Printf("--"+FgGreen+"Exported"+Reset+" %d faces with %d verticies\n", len(Faces), len(Verts))

    finished <- -1
}

func main(){
    // Verify we were called correctly
    if len(os.Args) < 2 {
        fmt.Println("Usage: go run objParser.go <OBJ File>");
        return
    }

    files := len(os.Args)
    finished := make(chan int)

    now := time.Now()

    for i := 1; i < files; i++ {
        go parseFile(os.Args[i], finished)
    }

    for i := 1; i < files; i++ {
        <- finished
    }

    fmt.Printf("Parsed %d files in %s\n", files-1, time.Since(now))
}
4

1 回答 1

6

您应该将 GOMAXPROCS 环境变量设置为最大可用处理器数。或者在执行时使用函数GOMAXPROCS

于 2012-09-18T18:47:55.037 回答