MST

星途 面试题库

面试题:Go语言协程定时任务的资源管理与性能优化

在高并发场景下,有多个不同间隔时间的定时任务(使用协程实现)同时运行,并且这些任务涉及到对共享资源(如数据库连接池、内存缓存等)的频繁访问。请阐述如何进行资源管理以避免竞态条件,以及如何对这些定时任务的性能进行优化,同时给出关键代码示例来展示你的思路。
23.8万 热度难度
编程语言Go

知识考点

AI 面试

面试题答案

一键面试

资源管理避免竞态条件

  1. 锁机制:使用互斥锁(Mutex)来保护共享资源。在访问共享资源前加锁,访问完成后解锁。例如在Go语言中:
package main

import (
    "fmt"
    "sync"
    "time"
)

var (
    mu    sync.Mutex
    count int
)

func task1() {
    for {
        mu.Lock()
        count++
        fmt.Println("Task1 incremented count:", count)
        mu.Unlock()
        time.Sleep(time.Second)
    }
}

func task2() {
    for {
        mu.Lock()
        count--
        fmt.Println("Task2 decremented count:", count)
        mu.Unlock()
        time.Sleep(2 * time.Second)
    }
}
  1. 读写锁(RWMutex):如果共享资源读操作远多于写操作,可以使用读写锁。读操作可以并发进行,写操作时加写锁,禁止其他读写操作。
package main

import (
    "fmt"
    "sync"
    "time"
)

var (
    rwmu  sync.RWMutex
    value int
)

func readTask() {
    for {
        rwmu.RLock()
        fmt.Println("Read value:", value)
        rwmu.RUnlock()
        time.Sleep(time.Second)
    }
}

func writeTask() {
    for {
        rwmu.Lock()
        value++
        fmt.Println("Write value:", value)
        rwmu.Unlock()
        time.Sleep(2 * time.Second)
    }
}
  1. 通道(Channel):通过通道来传递对共享资源的操作请求,由一个专门的协程负责处理这些请求,从而避免竞态条件。
package main

import (
    "fmt"
    "sync"
    "time"
)

type Request struct {
    op   string
    data int
}

func resourceHandler(requests chan Request) {
    var value int
    for req := range requests {
        switch req.op {
        case "read":
            fmt.Println("Read value:", value)
        case "write":
            value = req.data
            fmt.Println("Write value:", value)
        }
    }
}

func readTask(requests chan Request) {
    for {
        requests <- Request{op: "read"}
        time.Sleep(time.Second)
    }
}

func writeTask(requests chan Request) {
    for {
        requests <- Request{op: "write", data: 1}
        time.Sleep(2 * time.Second)
    }
}

定时任务性能优化

  1. 减少锁的持有时间:只在真正需要访问共享资源时加锁,尽快解锁。
  2. 合理设置定时任务间隔:避免过于频繁的任务调度,减少系统开销。
  3. 异步处理:对于一些可以异步执行的操作,使用异步方式处理,如将数据库写操作放入队列,由专门的协程处理。
  4. 连接池复用:对于数据库连接池等资源,合理设置连接池大小,提高连接复用率。

完整代码示例

package main

import (
    "fmt"
    "sync"
    "time"
)

// 共享资源
type SharedResource struct {
    data int
    mu   sync.Mutex
}

// 定时任务1
func task1(resource *SharedResource, wg *sync.WaitGroup) {
    defer wg.Done()
    for {
        resource.mu.Lock()
        resource.data++
        fmt.Println("Task1 incremented data:", resource.data)
        resource.mu.Unlock()
        time.Sleep(time.Second)
    }
}

// 定时任务2
func task2(resource *SharedResource, wg *sync.WaitGroup) {
    defer wg.Done()
    for {
        resource.mu.Lock()
        resource.data--
        fmt.Println("Task2 decremented data:", resource.data)
        resource.mu.Unlock()
        time.Sleep(2 * time.Second)
    }
}

func main() {
    var wg sync.WaitGroup
    resource := &SharedResource{}

    wg.Add(2)
    go task1(resource, &wg)
    go task2(resource, &wg)

    wg.Wait()
}