2024-08-08

go-cache 是一个 Go 语言的缓存库,用于简单的内存缓存。以下是一个简单的示例,展示如何使用 go-cache 来缓存数据。

首先,你需要安装 go-cache 包:




go get -u github.com/patrickmn/go-cache

下面是使用 go-cache 的一个简单示例:




package main
 
import (
    "fmt"
    "time"
 
    "github.com/patrickmn/go-cache"
)
 
func main() {
    // 创建一个新的缓存实例,设置默认的过期时间和清理间隔
    c := cache.New(5*time.Minute, 10*time.Minute)
 
    // 添加一个键值对到缓存中
    c.Set("key", "value", cache.DefaultExpiration)
 
    // 从缓存中获取键对应的值
    value, found := c.Get("key")
    if found {
        fmt.Println(value) // 输出: value
    }
 
    // 使用一个无限循环模拟长时间运行的应用程序
    for {
        // 每隔一段时间检查和清理过期的键
        time.Sleep(1 * time.Minute)
    }
}

在这个例子中,我们创建了一个缓存实例,并向其中添加了一个键值对。然后我们获取并打印了这个键对应的值。最后,我们使用一个无限循环来模拟长时间运行的应用程序,以便于我们可以观察缓存的过期和清理机制。

要深入阅读和理解 go-cache 的实现细节,你可以查看其 GitHub 仓库中的源代码,阅读 cache.go 文件,了解缓存的数据结构和基本操作,比如 SetGetDelete 等。

2024-08-08



package main
 
import (
    "fmt"
    "runtime"
    "runtime/debug"
)
 
func main() {
    // 设置GCPercent为100,确保每次垃圾回收都会打印信息
    debug.SetGCPercent(100)
 
    // 初始化内存分配统计信息
    m1 := new(runtime.MemStats)
    runtime.ReadMemStats(m1)
 
    // 分配内存
    a := make([]*byte, 1000000)
    for i := 0; i < len(a); i++ {
        b := new(byte)
        a[i] = b
    }
 
    // 再次读取内存统计信息并打印
    runtime.ReadMemStats(m1)
    fmt.Printf("分配内存后的统计信息: %+v\n", *m1)
 
    // 强制进行垃圾回收并打印回收结果
    runtime.GC()
    debug.FreeOSMemory()
 
    // 读取最终的内存统计信息并打印
    m2 := new(runtime.MemStats)
    runtime.ReadMemStats(m2)
    fmt.Printf("垃圾回收后的统计信息: %+v\n", *m2)
}

这段代码首先设置了GC百分比为100,确保每次垃圾回收都会打印信息。然后初始化了内存分配的统计信息并读取当前的内存状态。接下来,代码创建了一个包含100万个指针的切片,每个指针指向一个新分配的字节类型的内存地址。之后再次读取内存统计信息并打印。接着代码强制进行垃圾回收,并释放未使用的内存。最后,代码读取回收后的内存统计信息并打印。这个过程可以帮助理解Go语言的内存分配和垃圾回收机制。

2024-08-08

rotatelogs是一个用于日志轮转的库,通常在处理日志时使用,它可以按照设定的频率或大小对日志文件进行轮转,生成新的日志文件。在Go语言中,rotatelogs并不是一个标准库的一部分,它需要通过第三方库来使用。

以下是一个使用rotatelogs的例子:

首先,你需要安装rotatelogs库,可以通过以下命令进行安装:




go get github.com/lestrrat-go/file-rotatelogs

然后,你可以在Go代码中这样使用rotatelogs




package main
 
import (
    "github.com/lestrrat-go/file-rotatelogs"
    "io"
    "log"
    "time"
)
 
func main() {
    // 创建rotatelogs,日志文件名会以log.2006-01-02.15-04-05为格式进行命名,并且每天轮转一次
    writer, err := rotatelogs.New(
        "log.%Y-%m-%d.%H-%M-%S",
        rotatelogs.WithLinkName("./current.log"),  // 生成软链接指向最新日志文件
        rotatelogs.WithMaxAge(24*time.Hour),      // 文件最大保存时间
        rotatelogs.WithRotationTime(24*time.Hour), // 日志轮转的时间间隔
    )
    if err != nil {
        log.Fatalf("can't create rotatelogs: %s", err)
    }
 
    // 使用log.New()创建一个日志对象,writer设置为rotatelogs实例
    log.SetOutput(writer)
 
    // 进行日志记录
    log.Print("hello world")
 
    // 关闭writer,这里会关闭文件句柄
    if closer, ok := writer.(io.Closer); ok {
        closer.Close()
    }
}

在这个例子中,我们创建了一个每天轮转一次的日志文件,并且保存了24小时。同时,我们创建了一个软链接current.log指向最新的日志文件。这样,无论你通过log标准库记录信息还是通过writer记录信息,日志都会被记录到指定的文件中。最后,我们在程序结束时关闭了writer,确保文件句柄被正确关闭。

2024-08-08



package main
 
import (
    "fmt"
    "sync"
    "sync/atomic"
    "time"
)
 
var (
    wg           sync.WaitGroup
    counter int32
)
 
func main() {
    start := time.Now()
 
    for i := 0; i < 1000; i++ {
        wg.Add(1)
        go incrementCounter()
    }
 
    wg.Wait() // Wait for all goroutines to finish
    elapsed := time.Since(start)
 
    fmt.Printf("Counter: %d\n", counter)
    fmt.Printf("Time taken: %s\n", elapsed)
}
 
func incrementCounter() {
    defer wg.Done()
    atomic.AddInt32(&counter, 1)
}

这段代码使用了syncsync/atomic包来处理并发。wg.Add(1)为等待组添加一个计数,每个并发执行的任务会调用incrementCounter函数,它通过atomic.AddInt32(&counter, 1)以原子方式递增全局计数器counter。使用sync.WaitGroup确保主函数等待所有goroutine完成后再打印结果和耗时。这是一个简单的并发编程示例,展示了Go语言中的高效原子操作和并发处理。

2024-08-08



package main
 
import (
    "fmt"
    "github.com/hpcloud/tail"
    "os"
    "os/signal"
    "syscall"
)
 
func main() {
    // 创建一个tail.Config结构体实例,并设置配置
    cfg := tail.Config{
        ReOpen:    true,        // 当文件被删除或重命名后,自动尝试重新打开
        Follow:    true,        // 实时监控文件新增内容
        Location: &tail.SeekInfo{Offset: 0, Whence: os.SEEK_END}, // 从文件末尾开始读取
        MustExist: false,       // 如果文件不存在,不会返回错误
    }
 
    // 创建tail.Tail实例,并开始监控日志文件
    t, err := tail.TailFile("/path/to/your/logfile.log", cfg)
    if err != nil {
        fmt.Println("Error:", err)
        return
    }
 
    // 监听系统信号,如果接收到SIGINT或SIGTERM,则退出程序
    sigs := make(chan os.Signal, 1)
    signal.Notify(sigs, syscall.SIGINT, syscall.SIGTERM)
 
    go func() {
        <-sigs
        t.Stop()
    }()
 
    // 循环读取文件内容
    for line := range t.Lines {
        fmt.Println(line.Text)
    }
 
    fmt.Println("Exiting...")
}

这段代码使用了tail包来实现对日志文件的实时监控。它首先配置了tail.Config,然后使用tail.TailFile函数来创建一个监控实例。接着,它设置了一个系统信号监听,以便在程序接收到SIGINTSIGTERM信号时优雅地退出程序。最后,它在一个goroutine中循环读取文件的新内容,并将每行输出到控制台。

2024-08-08

在Linux下安装Go语言环境,可以按照以下步骤进行:

  1. 访问Go语言官方下载页面:https://golang.org/dl/
  2. 选择适合你的Linux平台的版本,通常是.tar.gz文件。例如,如果是amd64架构,通常是go1.18.1.linux-amd64.tar.gz
  3. 使用wgetcurl命令下载该文件:



wget https://dl.google.com/go/go1.18.1.linux-amd64.tar.gz

或者




curl -O https://dl.google.com/go/go1.18.1.linux-amd64.tar.gz
  1. 解压缩下载的文件到/usr/local目录:



sudo tar -C /usr/local -xzf go1.18.1.linux-amd64.tar.gz
  1. 配置环境变量。你需要将Go的可执行文件目录/usr/local/go/bin添加到PATH环境变量中,并设置GOPATH变量。编辑你的~/.bash_profile~/.bashrc文件,添加以下行:



export PATH=$PATH:/usr/local/go/bin
export GOPATH=$HOME/go
  1. 使更改生效:



source ~/.bash_profile
# 或者
source ~/.bashrc
  1. 验证安装是否成功:



go version

如果安装成功,上述命令将输出你安装的Go版本。

2024-08-08

在Golang中,并发可以通过几种方式实现,包括goroutines、channels和sync包。以下是一个简单的例子,展示了如何使用goroutines和channels来实现并发。




package main
 
import (
    "fmt"
    "sync"
    "time"
)
 
func worker(id int, wg *sync.WaitGroup, c chan string) {
    defer wg.Done() // 在函数退出时通知WaitGroup一个goroutine已经结束
    fmt.Printf("Worker %d starting\n", id)
    time.Sleep(time.Second) // 模拟工作
    c <- fmt.Sprintf("Worker %d done", id) // 将结果发送到channel
}
 
func main() {
    var wg sync.WaitGroup
    c := make(chan string) // 创建一个无缓冲的channel
 
    for i := 1; i <= 5; i++ {
        wg.Add(1) // 为每个goroutine增加一个计数
        go worker(i, &wg, c) // 启动goroutine
    }
 
    go func() {
        wg.Wait() // 等待所有goroutine完成
        close(c) // 关闭channel
    }()
 
    // 接收channel并打印结果
    for result := range c {
        fmt.Println(result)
    }
}

这段代码定义了一个worker函数,它会在一个goroutine中执行。main函数创建了一个channel和一个sync.WaitGroup,后者用于等待所有goroutines完成。每个worker在工作完成后,将一个结果发送到channel,然后退出。主goroutine中的wg.Wait()确保了程序在所有worker完成前不会退出。当所有worker都执行完毕并发送了结果之后,通过close(c)关闭channel,结束range循环,程序继续执行后面的代码。

2024-08-08

在Golang中,map是内置的数据类型,用于存储键值对的无序集合。以下是关于Golang map的一些关键点的解释和代码示例:

  1. 初始化map:



m := make(map[int]string)
  1. 插入元素:



m[1] = "Hello"
m[2] = "World"
  1. 读取元素:



value := m[1] // 返回 "Hello"
  1. 删除元素:



delete(m, 1) // 删除键为1的元素
  1. 循环访问map:



for key, value := range m {
    fmt.Println("Key:", key, "Value:", value)
}
  1. 扩容机制:

    当map中的元素数量超过2^B(B是map的buckets数量的对数)时,map会自动扩容。扩容操作涉及重新计算每个元素的位置,因此最好在创建时就指定合适的初始大小,以减少扩容次数。

例如,创建一个初始大小为1024的map:




m := make(map[int]string, 1024)

以上是Golang map的基本操作和一个扩容机制的简单说明。

2024-08-08



package main
 
import (
    "fmt"
    "sync"
    "time"
)
 
func main() {
    // 使用WaitGroup来同步不同的goroutine
    var wg sync.WaitGroup
    
    // 创建一个channel用来传递整数
    c := make(chan int)
    
    // 启动一个goroutine来生成数字并发送到channel
    wg.Add(1)
    go func() {
        defer wg.Done()
        for i := 0; i < 5; i++ {
            c <- i
            time.Sleep(time.Millisecond * 500) // 模拟耗时操作
        }
        close(c) // 使用close函数来表示channel已经完成发送
    }()
    
    // 启动另一个goroutine来接收并打印channel中的数字
    wg.Add(1)
    go func() {
        defer wg.Done()
        for n := range c {
            fmt.Println(n)
        }
    }()
    
    // 等待所有goroutine完成
    wg.Wait()
}

这段代码使用了Go语言的并发特性来实现一个简单的场景:一个goroutine生成数字并发送到一个channel中,另一个goroutine从channel中接收数字并打印。使用了sync.WaitGroup来同步两个goroutine,确保主goroutine在两个辅助goroutine完成工作之前不会退出。代码简洁且易于理解,展示了Go语言在并发编程中的优秀表现。

2024-08-08

go getgo install 是 Go 语言中用于获取和安装包的两个命令。

  1. go get

go get 命令会自动获取并安装代码依赖包。它会从远程代码仓库(例如 GitHub、Google Code、Bitbucket 等)下载并安装包。如果该包为 Go 的标准库中的一部分,或者在 GOPATH 环境变量定义的工作空间内,那么 go get 会更新它。

示例:




go get -u github.com/gin-gonic/gin

这个命令会获取并安装最新的 Gin Web 框架。-u 参数表示更新已经存在的包并下载新的包。

  1. go install

go install 命令会编译并安装指定的包。和 go get 一样,它也会自动处理包的依赖关系。不同的是,go install 会将编译后的结果安装到工作空间的 pkg 目录下,并且会将生成的目标文件(如库文件、可执行文件等)放在 $GOPATH/bin 目录下。

示例:




go install github.com/gin-gonic/gin

这个命令会编译并安装 Gin Web 框架。

注意:go getgo install 都需要网络连接,因为它们需要从远程仓库下载代码。