Go内存与性能

821 阅读5分钟

「这是我参与11月更文挑战的第12天,活动详情查看:2021最后一次更文挑战

生命不息,学习不止

题外话

周五了,明天就可以休息了,奋斗了一周想办法犒劳自己一下吧,哟,这个必x客的披萨看着不错,行,就搞个必x客吧……11月13日新闻,神秘人收购必x客,改名必b客

又是乏味的一天…… 人生就是这么简简单单

话说今天升温了,真不错

在这里插入图片描述 废话不多说,上货 在这里插入图片描述

空间复杂度与时间复杂度

1、时间复杂度

(1)时间频度 一个算法执行所耗费的时间,从理论上是不能算出来的,必须上机运行测试才能知道。但我们不可能也没有必要对每个算法都上机测试,只需知道哪个算法花费的时间多,哪个算法花费的时间少就可以了。并且一个算法花费的时间与算法中语句的执行次数成正比例,哪个算法中语句执行次数多,它花费时间就多。一个算法中的语句执行次数称为语句频度或时间频度。记为T(n)。 (2)时间复杂度 在刚才提到的时间频度中,n称为问题的规模,当n不断变化时,时间频度T(n)也会不断变化。但有时我们想知道它变化时呈现什么规律。为此,我们引入时间复杂度概念。 一般情况下,算法中基本操作重复执行的次数是问题规模n的某个函数,用T(n)表示,若有某个辅助函数f(n),使得当n趋近于无穷大时,T(n)/f(n)的极限值为不等于零的常数,则称f(n)是T(n)的同数量级函数。记作T(n)=O(f(n)),称O(f(n)) 为算法的渐进时间复杂度,简称时间复杂度。

2.算法的空间复杂度

空间复杂度(Space Complexity)是对一个算法在运行过程中临时占用存储空间大小的量度。 一个算法在计算机存储器上所占用的存储空间,包括存储算法本身所占用的存储空间,算法的输入输出数据所占用的存储空间和算法在运行过程中临时占用的存储空间这三个方面。

举个例子

在这里插入图片描述

斐波那契数列

斐波那契数列(Fibonacci sequence),又称黄金分割数列,因数学家莱昂纳多·斐波那契(Leonardo Fibonacci)以兔子繁殖为例子而引入,故又称为“兔子数列” 斐波那契数列:1, 1, 2, 3, 5, 8, 13, 21, 34, 55, 89, 144, 233…… 这个数列从第3项开始,每一项都等于前两项之和 我们试着求一下前40项的各项值,并看看花费多长时间 上代码

package main
import (
    "fmt"
    "time"
)
func main() {
    result := 0
    start := time.Now()
    for i := 1; i <= 40; i++ {
        result = fibonacci(i)
        fmt.Printf("数列第 %d 位: %d\n", i, result)
    }
    end := time.Now()
    delta := end.Sub(start)
    fmt.Printf("程序的执行时间为: %s\n", delta)
}
func fibonacci(n int) (res int) {
    if n <= 2 {
        res = 1
    } else {
        res = fibonacci(n-1) + fibonacci(n-2)
    }
    return
}

运行结果太长了,我就给你们截一部份

数列第 1 位: 1

数列第 2 位: 1

数列第 3 位: 2

数列第 4 位: 3

...

数列第 39 位: 63245986

数列第 40 位: 102334155

程序的执行时间为: 2.2848865s

大概就是这样,电脑性能不同,执行时间也会有所区别

使用内存缓存以提高性能

大部分提高性能或者减少算法时间复杂度的方式都是拿空间来交换, 其中内存缓存是很常见的一种 内存缓存的实现思路是在计算得到第 n 个数的同时,将它的值保存到数组中索引为 n 的位置上,在后续的计算中先在数组中查找所需要的值是否计算过,如果找到了,则直接从数组中获取,如果没找到,则再进行计算

package main
import (
    "fmt"
    "time"
)
const LIM = 41
var fibs [LIM]uint64
func main() {
    var result uint64 = 0
    start := time.Now()
    for i := 1; i < LIM; i++ {
        result = fibonacci(i)
        fmt.Printf("数列第 %d 位: %d\n", i, result)
    }
    end := time.Now()
    delta := end.Sub(start)
    fmt.Printf("程序的执行时间为: %s\n", delta)
}
func fibonacci(n int) (res uint64) {
    // 记忆化:检查数组中是否已知斐波那契(n)
    if fibs[n] != 0 {
        res = fibs[n]
        return
    }
    if n <= 2 {
        res = 1
    } else {
        res = fibonacci(n-1) + fibonacci(n-2)
    }
    fibs[n] = res
    return
}

同样截取部分结果 运行结果如下所示:

数列第 1 位: 1

数列第 2 位: 1

数列第 3 位: 2

数列第 4 位: 3

...

数列第 39 位: 63245986

数列第 40 位: 102334155

程序的执行时间为: 0.0149603s

通过运行结果可以看出,同样获取数列第 40 位的数字,使用内存缓存后所用的时间为 0.0149603 秒,对比之前未使用内存缓存时的执行效率,可见内存缓存的优势还是相当明显的。

你以为结束了

本次例子使用的是递归的方实,其实递归就是非常消耗内存的方实。 小问题:如何不使用递归完成斐波那契数列的实现?

上期问题:读取ini文件后,如何通过键去修改值呢?

上期答案:通过file.WriteAt方法内容覆盖写入

在这里插入图片描述

大家看完发现有什么错误,写在下面吧!跟我黑虎阿福比划比划! 在这里插入图片描述