首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >问答首页 >在golang中,为什么当我使用缓冲(异步)通道时,我的程序运行得更慢?

在golang中,为什么当我使用缓冲(异步)通道时,我的程序运行得更慢?
EN

Stack Overflow用户
提问于 2013-05-22 21:27:44
回答 2查看 3.8K关注 0票数 4

我对高丽来说是个新手,所以我相信这个问题主要是因为我的一些概念上的缺陷。

在golang中,我们可以有两种类型的通道:非缓冲的和异步的(分别是同步的和异步的)。

代码语言:javascript
运行
复制
unbufferedChan := make(chan string)
bufferedChan := make(chan string, 100)

通过非缓冲通道进行通信的两个猩猩必须互相等待。也就是说,接收方阻塞直到发送方发送,而发送方阻塞直到接收方接收。

在缓冲的情况下,只有当信道为空时,接收器才会阻塞。只有当频道已满时,发送方才会阻塞。

通过使用缓冲通道,我期望减少goroutines阻塞的时间,从而提高代码的速度。相反,一切都变慢了。与我的预期相反(即“缓冲更有效”),未缓冲的通道最终大大加快了速度。

这是所有的密码。你需要先go get code.google.com/p/go-html-transform/html/transform .

代码语言:javascript
运行
复制
package main

import (
    "fmt"
    "math/rand"
    "os"
    "sync"
    "time"
    sel "code.google.com/p/go-html-transform/css/selector"
    h5 "code.google.com/p/go-html-transform/h5"
    gnhtml "code.google.com/p/go.net/html"
)

// Find a specific HTML element and return its textual element children.
func main() {
    test := `
<html>
  <head>
    <title>This is the test document!</title>
    <style>
      header: color=blue;
    </style>
  </head>
  <body>
    <div id="h" class="header">This is some text</div>
  </body>
</html>`

    // Get a parse tree for this HTML
    h5tree, err := h5.NewFromString(test)
    if err != nil {
        die(err)
    }
    n := h5tree.Top()

    // Create a Chain object from a CSS selector statement
    chn, err := sel.Selector("#h")
    if err != nil {
        die(err)
    }

    // Find the item.  Should be a div node with the text "This is some text"
    h := chn.Find(n)[0]

    // run our little experiment this many times total
    var iter int = 100000

    // When buffering, how large shall the buffer be?
    var bufSize uint = 100

    // Keep a running total of the number of times we've tried buffered
    //   and unbuffered channels.
    var bufCount int = 0
    var unbufCount int =0

    // Keep a running total of the number of nanoseconds that have gone by.
    var bufSum int64 = 0
    var unbufSum int64 = 0

    // Call the function {iter} times, randomly choosing whether to use a
    //   buffered or unbuffered channel.
    for i := 0; i < iter; i++ {
        if rand.Float32() < 0.5 {
            // No buffering
            unbufCount += 1
            startTime := time.Now()
            getAllText(h, 0)
            unbufSum += time.Since(startTime).Nanoseconds()     
        } else {
            // Use buffering
            bufCount += 1
            startTime := time.Now()
            getAllText(h, bufSize)
            bufSum += time.Since(startTime).Nanoseconds()
        }
    }
    unbufAvg := unbufSum / int64(unbufCount)
    bufAvg := bufSum / int64(bufCount)

    fmt.Printf("Unbuffered average time (ns): %v\n", unbufAvg)
    fmt.Printf("Buffered average time (ns): %v\n", bufAvg)
}

// Kill the program and report the error
func die(err error) {
    fmt.Printf("Terminating: %v\n", err.Error())
    os.Exit(1)
}

// Walk through all of a nodes children and construct a string consisting
//   of c.Data where c.Type == TextNode
func getAllText(n *gnhtml.Node, bufSize uint) string {
    var texts chan string
    if bufSize == 0 {
        // unbuffered, synchronous
        texts = make(chan string)
    } else {
        // buffered, asynchronous
        texts = make(chan string, bufSize)
    }

    wg := sync.WaitGroup{}


    // Go walk through all n's child nodes, sending only textual data
    //   over the texts channel.
    wg.Add(1)
    nTree := h5.NewTree(n)
    go func () {
        nTree.Walk(func (c *gnhtml.Node) {
            if c.Type == gnhtml.TextNode {
                texts <- c.Data
            }
        })

        close(texts)
        wg.Done()
    }()

    // As text data comes in over the texts channel, build up finalString
    wg.Add(1)
    finalString := ""
    go func () {
        for t := range texts {
            finalString += t
        }

        wg.Done()
    }()

    // Return finalString once both of the goroutines have finished.
    wg.Wait()
    return finalString
}

运行该程序10次,结果如下:

代码语言:javascript
运行
复制
Buffered average time (ns): 32088
Buffered average time (ns): 32183
Buffered average time (ns): 35091
Buffered average time (ns): 35798
Buffered average time (ns): 36966
Buffered average time (ns): 38707
Buffered average time (ns): 39464
Buffered average time (ns): 40021
Buffered average time (ns): 41063
Buffered average time (ns): 46248
Unbuffered average time (ns): 18265
Unbuffered average time (ns): 18804
Unbuffered average time (ns): 20268
Unbuffered average time (ns): 20401
Unbuffered average time (ns): 21652
Unbuffered average time (ns): 22630
Unbuffered average time (ns): 22907
Unbuffered average time (ns): 23326
Unbuffered average time (ns): 24133
Unbuffered average time (ns): 27546
EN

回答 2

Stack Overflow用户

回答已采纳

发布于 2013-05-22 21:42:55

实际上,我可能刚刚弄明白了。我认为额外的时间是由于创建了一个100元缓冲通道。

我再次运行该程序,这次使用的缓冲区大小为10 (仍高于我的小测试程序所需的),而不是100 (原始缓冲区大小)。

以下是研究结果:

代码语言:javascript
运行
复制
Buffered average time (ns): 21930
Buffered average time (ns): 22721
Buffered average time (ns): 23011
Buffered average time (ns): 23707
Buffered average time (ns): 27701
Buffered average time (ns): 28325
Buffered average time (ns): 28851
Buffered average time (ns): 29641
Buffered average time (ns): 30417
Buffered average time (ns): 32600
Unbuffered average time (ns): 21077
Unbuffered average time (ns): 21490
Unbuffered average time (ns): 22332
Unbuffered average time (ns): 22584
Unbuffered average time (ns): 26438
Unbuffered average time (ns): 26824
Unbuffered average time (ns): 27322
Unbuffered average time (ns): 27926
Unbuffered average time (ns): 27985
Unbuffered average time (ns): 30322

这些数字更接近彼此。

票数 3
EN

Stack Overflow用户

发布于 2013-05-28 19:00:12

外部化测试中缓冲区的创建:

代码语言:javascript
运行
复制
package main

import (
    "fmt"
    "math/rand"
    "os"
    "sync"
    "time"
    sel "code.google.com/p/go-html-transform/css/selector"
    h5 "code.google.com/p/go-html-transform/h5"
    gnhtml "code.google.com/p/go.net/html"
)

// Find a specific HTML element and return its textual element children.
func main() {
    test := `
<html>
  <head>
    <title>This is the test document!</title>
    <style>
      header: color=blue;
    </style>
  </head>
  <body>
    <div id="h" class="header">This is some text</div>
  </body>
</html>`

    // Get a parse tree for this HTML
    h5tree, err := h5.NewFromString(test)
    if err != nil {
        die(err)
    }
    n := h5tree.Top()

    // Create a Chain object from a CSS selector statement
    chn, err := sel.Selector("#h")
    if err != nil {
        die(err)
    }

    // Find the item.  Should be a div node with the text "This is some text"
    h := chn.Find(n)[0]

    // run our little experiment this many times total
    var iter int = 100000

    // When buffering, how large shall the buffer be?
    var bufSize uint = 100

    // Keep a running total of the number of times we've tried buffered
    //   and unbuffered channels.
    var bufCount int = 0
    var unbufCount int =0

    // Keep a running total of the number of nanoseconds that have gone by.
    var bufSum int64 = 0
    var unbufSum int64 = 0

    // Call the function {iter} times, randomly choosing whether to use a
    //   buffered or unbuffered channel.
    for i := 0; i < iter; i++ {
        if rand.Float32() < 0.5 {
            // No buffering
            unbufCount += 1
            texts := make(chan string)
            startTime := time.Now()
            getAllText(h, 0, texts)
            unbufSum += time.Since(startTime).Nanoseconds()     
        } else {
            // Use buffering
            bufCount += 1
            texts := make(chan string, bufSize)
            startTime := time.Now()
            getAllText(h, bufSize, texts)
            bufSum += time.Since(startTime).Nanoseconds()
        }
    }
    unbufAvg := unbufSum / int64(unbufCount)
    bufAvg := bufSum / int64(bufCount)

    fmt.Printf("Unbuffered average time (ns): %v\n", unbufAvg)
    fmt.Printf("Buffered average time (ns): %v\n", bufAvg)
}

// Kill the program and report the error
func die(err error) {
    fmt.Printf("Terminating: %v\n", err.Error())
    os.Exit(1)
}

// Walk through all of a nodes children and construct a string consisting
//   of c.Data where c.Type == TextNode
func getAllText(n *gnhtml.Node, bufSize uint, texts chan string) string {
    wg := sync.WaitGroup{}


    // Go walk through all n's child nodes, sending only textual data
    //   over the texts channel.
    wg.Add(1)
    nTree := h5.NewTree(n)
    go func () {
        nTree.Walk(func (c *gnhtml.Node) {
            if c.Type == gnhtml.TextNode {
                texts <- c.Data
            }
        })

        close(texts)
        wg.Done()
    }()

    // As text data comes in over the texts channel, build up finalString
    wg.Add(1)
    finalString := ""
    go func () {
        for t := range texts {
            finalString += t
        }

        wg.Done()
    }()

    // Return finalString once both of the goroutines have finished.
    wg.Wait()
    return finalString
}

有了这个(在启动定时器之前移动通道创建),我就得到了如下结果:

代码语言:javascript
运行
复制
Buffered average time (ns): 2649
Buffered average time (ns): 2655
Buffered average time (ns): 2657
Buffered average time (ns): 2695
Buffered average time (ns): 2695
Buffered average time (ns): 2699
Buffered average time (ns): 2719
Buffered average time (ns): 2724
Buffered average time (ns): 2793
Buffered average time (ns): 3101
Unbuffered average time (ns): 2997
Unbuffered average time (ns): 3005
Unbuffered average time (ns): 3027
Unbuffered average time (ns): 3031
Unbuffered average time (ns): 3048
Unbuffered average time (ns): 3062
Unbuffered average time (ns): 3086
Unbuffered average time (ns): 3092
Unbuffered average time (ns): 3095
Unbuffered average time (ns): 3191

为了改进,解决方案可能是在可能的情况下保持通道开放。

票数 2
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/16701870

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档