基准测试的缓冲写入

    writingBU.go 程序使用随机生成的数据来产生虚拟文件。这个程序的变量是缓冲的大小和输出文件的大小。

    writingBU.go 的第一部分如下:

    writingBU.go 的第二段代码如下:

    1. func createBuffer(buf *[]byte, count int) {
    2. *buf = make([]byte, count)
    3. if count == 0 {
    4. return
    5. }
    6. for i := 0; i < count; i++ {
    7. intByte := byte(random(0, 100))
    8. if len(*buf) > count {
    9. return
    10. }
    11. *buf = append(*buf, intByte)
    12. }
    13. }

    writingBU.go 的第三部分如下:

    1. func Create(dst string, b, f int) error {
    2. _, err := os.Stat(dst)
    3. if err == nil {
    4. return fmt.Error("File %s already exists.", dst)
    5. }
    6. destination, err := os.Create(dst)
    7. if err != nil {
    8. return err
    9. }
    10. defer destination.Close()
    11. panic(err)
    12. }
    13. buf := make([]byte, 0)
    14. for {
    15. buf = buf[:b]
    16. if _, err := destination.Write(buf); err != nil {
    17. return err
    18. }
    19. if f < 0 {
    20. break
    21. }
    22. f = f - len(buf)
    23. }
    24. return err
    25. }

    程序中的 Create() 函数做了所有工作,他是需要进行基准测试的函数。

    注意如果缓冲大小和文件大小不是 Create() 函数的签名的一部分,在给 Create() 函数写基准测试函数时您将遇到问题,因为您需要使用 BUFFERSIZEFILESIZE 全局变量,它们都是在 writingBU.gomain() 函数中初始化的。

    这将是一个难点在 writingBU_test.go 文件中。这意味着为了给一个函数创建一个基准测试,您应该在您写代码时就考虑这个问题。

    writingBU.go 的其余代码如下:

    1. err = os.Remove(output)
    2. if err != nil {
    3. fmt.Println(err)
    4. }
    5. }

    尽管在 main() 函数里调用 os.Remove() 删除了临时文件,但没有在基准测试函数中调用它,在基准测试函数中调用它比较简单,所以这不是问题。

    在一台有 SSD 硬盘的 macOS High Sierra 机器上执行 writingBU.go 俩次,用 time(1) 工具来检测程序产生如下输出但速度:

    1. $ time go run writingBU.go 1 100000
    2. real 0m1.193s
    3. sys 0m0.809s
    4. $ time go run writingBU.go 10 100000
    5. real 0m0.283s
    6. user 0m0.195s
    7. sys 0m0.228s

    尽管这显示出写缓冲的大小对程序的性能起到关键作用,但我们需要更具体更准确。因此,我们来写基准测试函数存储为 writingBU_test.go

    writingBU_test.go 的第一部分如下:

    您会记得这不是一个有效的基准测试函数。

    writingBU_test.go 的第二段代码如下:

    1. func Benchmark1Create(b *testing.B) {
    2. benchmarkCreate(b, 1, 1000000)
    3. }
    4. func Benchmark2Create(b *testing.B) {
    5. benchmarkCreate(b, 2, 1000000)
    6. }
    1. func Benchmark4Create(b *testing.B) {
    2. benchmarkCreate(b, 4, 1000000)
    3. }
    4. func Benchmark10Create(b *testing.B) {
    5. benchmarkCreate(b, 10, 1000000)
    6. }
    7. func Benchmark1000Create(b *testing.B) {
    8. benchmarkCreate(b, 1000, 1000000)
    9. }

    这里我们写了五个基准测试函数来检测 benchmarkCreate() 函数的性能,它用写缓冲大小变量检测 Create() 函数的性能。

    writingBU.gowritingBU_test.go 文件执行 go test 将产生如下输出:

    下面的输出也检测了基准测试函数的内存分配:

    11.9 基准测试的缓冲写入 - 图2

    现在来解释一下这俩个 命令的输出。

    很明显使用一个大小为 1 个字节的写缓冲是完全无效的并且缓冲所有的操作。另外,这样的缓冲大小需要更多的内存操作,这也使程序运行的更慢!

    当决定用 10 个字节的写缓冲时,这会变的更快。最后,这个结果显示使用 1,000 字节的写缓冲没有比使用 10 字节的快 100 倍,这意味着在速度和写缓冲大小之间的最佳点是在这俩个值之间。