使用Goroutine实际上需要更长的执行时间

huangapple go评论89阅读模式
英文:

Using a Goroutine actually takes longer to execute

问题

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

$ go run objParser.go ak47.obj extincteur_obj.obj
--从ak47.obj创建ak47.json3d
--导出了85772个面和89088个顶点
--从extincteur_obj.obj创建extincteur_obj.json3d
--导出了150316个面和151425个顶点
在8.4963秒内解析了2个文件

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

$ go run objParser.go ak47.obj extincteur_obj.obj
--从ak47.obj创建ak47.json3d
--从extincteur_obj.obj创建extincteur_obj.json3d
--导出了85772个面和89088个顶点
--导出了150316个面和151425个顶点
在10.23137秒内解析了2个文件

打印的顺序是我预期的,因为解析是交错进行的,但我不知道为什么实际上需要更长的时间!代码非常长,我剪掉了一些,但仍然很长,对此很抱歉!

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))
}
英文:

I'm sure that I'm doing something wrong, I have a Go program that parses in 3D models in OBJ format and outputs a json object. When I run it without adding in goroutines I get the following output:

$ 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

Then I added in the goroutines and I get this output:

$ 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

The order of how it's printed is what I expected given the interlacing of the parsing but I have no idea why it actually takes longer! The code is pretty long, I snipped what I could but it's still pretty long, sorry about that!

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, &quot;.obj&quot;, &quot;.json3d&quot;, -1)
parseMaterial = false
fmt.Printf(&quot;--&quot;+FgGreen+&quot;Creating&quot;+Reset+&quot; %s from %s\n&quot;, outName, inName)
var err error
var part []byte
var prefix bool
if objFile, err = os.Open(inName); err != nil {
fmt.Println(FgRed+&quot;!!Failed to open input file!!&quot;+Reset)
return
}
if jsonFile, err = os.Create(outName); err != nil {
fmt.Println(FgRed+&quot;!!Failed to create output file!!&quot;+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, &quot;v &quot;)) {
Verts = append(Verts, parseVertex(line))
} else if(strings.Contains(line, &quot;vt &quot;)) {
Texs = append(Texs, parseTexCoord(line))
} else if(strings.Contains(line, &quot;f &quot;)) {
Faces = append(Faces, parseFace(line, Verts, Texs))
} else if(strings.Contains(line, &quot;mtllib &quot;)) {
mtlName := strings.Split(line, &quot; &quot;)[1]
if mtlFile, err = os.Open(mtlName); err != nil {
fmt.Printf(&quot;--&quot;+FgRed+&quot;Failed to find material file: %s\n&quot;+Reset, mtlName)
parseMaterial = false
} else {
parseMaterial = true
}
}
buffer.Reset()
}
}
if err == io.EOF {
err = nil
}
objFile.Close()
// Write out the data
writer.WriteString(&quot;{\&quot;obj\&quot;:[\n&quot;);
// Write out the verts
writer.WriteString(&quot;{\&quot;vrt\&quot;:[\n&quot;);
for i, vert := range Verts {
writer.WriteString(vert.String())
if i &lt; len(Verts) - 1 { writer.WriteString(&quot;,&quot;) }
writer.WriteString(&quot;\n&quot;)
}
// Write out the faces
writer.WriteString(&quot;],\&quot;fac\&quot;:[\n&quot;)
for i, face := range Faces {
writer.WriteString(face.String(true))
if i &lt; len(Faces) - 1 { writer.WriteString(&quot;,&quot;) }
writer.WriteString(&quot;\n&quot;)
}
// Write out the normals
writer.WriteString(&quot;],\&quot;nrm\&quot;:[&quot;)
for i, face := range Faces {
writer.WriteString(&quot;[&quot;)
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(&quot;[%f,%f,%f]&quot;, x, y, z)
writer.WriteString(normal)
if(j &lt; len(face.verts)-1) { writer.WriteString(&quot;,&quot;) }
}
writer.WriteString(&quot;]&quot;)
//writer.WriteString(&quot;[0, 1, 0]&quot;)
if i &lt; len(Faces) - 1 { writer.WriteString(&quot;,&quot;) }
writer.WriteString(&quot;\n&quot;)
}
// Write out the tex coords
writer.WriteString(&quot;],\&quot;tex\&quot;:[&quot;)
for i, face := range Faces {
writer.WriteString(&quot;[&quot;)
writer.WriteString(face.tex[0].String())
writer.WriteString(&quot;,&quot;)
writer.WriteString(face.tex[1].String())
writer.WriteString(&quot;,&quot;)
writer.WriteString(face.tex[2].String())
writer.WriteString(&quot;]&quot;)
if i &lt; len(Faces) - 1 { writer.WriteString(&quot;,&quot;) }
writer.WriteString(&quot;\n&quot;)
}
// Close obj block
writer.WriteString(&quot;]}]&quot;);
if parseMaterial {
writer.WriteString(&quot;,mat:[{&quot;);
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, &quot;map_Kd &quot;)) {
parts := strings.Split(line, &quot; &quot;)
entry := fmt.Sprintf(&quot;\&quot;t\&quot;:\&quot;%s\&quot;,&quot;, parts[1])
writer.WriteString(entry)
width, height := 256, 256
var imageFile *os.File
if imageFile, err = os.Open(parts[1]); err != nil {
fmt.Printf(&quot;--&quot;+FgRed+&quot;Failed to find %s, defaulting to 256x256&quot;+Reset+&quot;\n&quot;, 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(&quot;--&quot;+FgGreen+&quot;Verifing&quot;+Reset+&quot; that %s is %dpx x %dpx\n&quot;, parts[1], width, height)
}
size := fmt.Sprintf(&quot;\&quot;w\&quot;:%d,\&quot;h\&quot;:%d,&quot;, width, height)
writer.WriteString(size)
} else if(strings.Contains(line, &quot;Kd &quot;)) {
parts := strings.Split(line, &quot; &quot;)
entry := fmt.Sprintf(&quot;\&quot;r\&quot;:%s, \&quot;g\&quot;:%s, \&quot;b\&quot;:%s,&quot;, parts[1], parts[2], parts[3])
writer.WriteString(entry)
}
buffer.Reset()
}
}
if err == io.EOF {
err = nil
}
writer.WriteString(&quot;\&quot;res\&quot;:100,\&quot;uv\&quot;:true}]&quot;);
}
// Close json
writer.WriteString(&quot;}&quot;);
writer.Flush()
jsonFile.Close()
fmt.Printf(&quot;--&quot;+FgGreen+&quot;Exported&quot;+Reset+&quot; %d faces with %d verticies\n&quot;, len(Faces), len(Verts))
finished &lt;- -1
}
func main(){
// Verify we were called correctly
if len(os.Args) &lt; 2 {
fmt.Println(&quot;Usage: go run objParser.go &lt;OBJ File&gt;&quot;);
return
}
files := len(os.Args)
finished := make(chan int)
now := time.Now()
for i := 1; i &lt; files; i++ {
go parseFile(os.Args[i], finished)
}
for i := 1; i &lt; files; i++ {
&lt;- finished
}
fmt.Printf(&quot;Parsed %d files in %s\n&quot;, files-1, time.Since(now))
}

答案1

得分: 6

你应该为Go设置GOMAXPROCS环境变量,以便将可用处理器的数量设置为最大值。或者在执行时使用GOMAXPROCS函数。

英文:

You should set GOMAXPROCS environment variable for go to the maximum number of usable processors. Or use function GOMAXPROCS at executing time.

huangapple
  • 本文由 发表于 2012年9月19日 02:33:09
  • 转载请务必保留本文链接:https://go.coder-hub.com/12482910.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定