for循环

时间:2017-02-06 03:03:47

标签: go

我做了一个测试,看看select的性能,发现结果不是 好。 go版本是1.7.3

package main

import (
    "fmt"
    "log"
    "os"
    "runtime/pprof"
    "time"
)

var serverDone = make(chan struct{})
var serverDone1 = make(chan struct{})
var serverDone2 = make(chan struct{})
var serverDone3 = make(chan struct{})
var serverDone4 = make(chan struct{})
var serverDone5 = make(chan struct{})

func main() {
    f, err := os.Create("cpu.pprof")
    if err != nil {
        log.Fatal(err)
    }
    pprof.StartCPUProfile(f)
    defer pprof.StopCPUProfile()

    for i := 0; i < 1000; i++ {
        go messageLoop()
    }
    <-time.After(10 * time.Second)
    close(serverDone)
    fmt.Println("finished")
}

func messageLoop() {
    var ticker = time.NewTicker(100 * time.Millisecond)
    defer ticker.Stop()
    var counter = 0
    for {
        select {
        case <-serverDone:
            return
        case <-serverDone1:
            return
        // case <-serverDone2:
        //  return
        // case <-serverDone3:
        //  return
        // case <-serverDone4:
        //  return
        // case <-serverDone5:
        //  return
        case <-ticker.C:
            counter += 1
        }
    }
}

运行上述代码时,每次添加serverDone案例时,您都会发现CPU(在我的书中,大约5%)。
当删除所有serverDone案例时,CPU大约为5%,这并不好 如果我将全局锁定对象(如serverDone)转换为本地,性能会更好,但仍然不够好。

谁知道我的情况有什么问题,或者select语句的正确用法是什么?

1 个答案:

答案 0 :(得分:5)

简答:频道使用互斥锁。更多频道意味着更多futex系统调用

这是关于节目的问题。

包含7个select语句的代码,等待7 channels

% time     seconds  usecs/call     calls    errors syscall
------ ----------- ----------- --------- --------- ----------------
 98.20    0.424434          13     33665      6061 futex
  1.09    0.004731          10       466           sched_yield
  0.47    0.002038          30        67           select
  0.11    0.000484           4       114           rt_sigaction
  0.05    0.000203           5        41         8 rt_sigreturn
  0.03    0.000128           9        15           mmap
  0.02    0.000081          27         3           clone
  0.01    0.000052           7         8           rt_sigprocmask
  0.01    0.000032          32         1           openat
  0.00    0.000011           4         3           setitimer
  0.00    0.000009           5         2           sigaltstack
  0.00    0.000008           8         1           munmap
  0.00    0.000006           6         1           execve
  0.00    0.000006           6         1           sched_getaffinity
  0.00    0.000004           4         1           arch_prctl
  0.00    0.000004           4         1           gettid
  0.00    0.000000           0         2         2 restart_syscall
------ ----------- ----------- --------- --------- ----------------
100.00    0.432231                 34392      6071 total

包含3个select语句的代码,等待3 channels

% time     seconds  usecs/call     calls    errors syscall
------ ----------- ----------- --------- --------- ----------------
 90.47    0.118614          11     10384      1333 futex
  6.64    0.008704          11       791           sched_yield
  2.06    0.002706          23       120           select
  0.39    0.000512           4       114           rt_sigaction
  0.14    0.000181           8        22         2 rt_sigreturn
  0.10    0.000131           9        15           mmap
  0.05    0.000060          60         1           openat
  0.04    0.000057          19         3           setitimer
  0.04    0.000051          17         3           clone
  0.03    0.000045           6         8           rt_sigprocmask
  0.01    0.000009           9         1           execve
  0.01    0.000009           5         2           sigaltstack
  0.01    0.000009           9         1           sched_getaffinity
  0.01    0.000008           8         1           munmap
  0.01    0.000007           7         1           arch_prctl
  0.00    0.000005           5         1           gettid
------ ----------- ----------- --------- --------- ----------------
100.00    0.131108                 11468      1335 total

很明显,futex次呼叫的数量与频道数量成正比,而futex系统呼叫是这种性能的原因。

以下是

的解释

您可以在以下文件src/runtime/chan.go中找到频道实施。

以下是hchan频道的结构

type hchan struct {
    qcount   uint           // total data in the queue
    dataqsiz uint           // size of the circular queue
    buf      unsafe.Pointer // points to an array of dataqsiz elements
    elemsize uint16
    closed   uint32
    elemtype *_type // element type
    sendx    uint   // send index
    recvx    uint   // receive index
    recvq    waitq  // list of recv waiters
    sendq    waitq  // list of send waiters
    lock     mutex
}

在runtime2.go中定义了一个Lock嵌入式结构,它可以作为互斥锁(futex)或信号量,具体取决于操作系统。

因此,随着频道数量的增加,会有更多futex system call次呼叫,这会影响性能

您可以在futex(2)Channels in steroids

中详细了解这些内容