MST

星途 面试题库

面试题:Go空接口在并发编程与扩展性方面的深度应用

在一个高并发的Go应用程序中,有多个不同类型的任务需要通过通道进行传递和处理。请利用空接口设计一个通用的任务调度和处理框架,要求具备良好的扩展性,能够方便地添加新类型的任务处理逻辑,同时保证并发安全。请详细阐述设计思路并给出核心代码实现。
50.4万 热度难度
编程语言Go

知识考点

AI 面试

面试题答案

一键面试

设计思路

  1. 任务定义:使用空接口 interface{} 来表示各种不同类型的任务,这样可以让框架接受任何类型的任务。
  2. 任务队列:使用通道 chan interface{} 作为任务队列,用于传递任务。
  3. 任务处理器:为每种任务类型定义对应的处理函数,这些函数可以注册到框架中。
  4. 调度器:负责从任务队列中取出任务,并根据任务类型调用相应的处理函数,同时保证并发安全。

核心代码实现

package main

import (
    "fmt"
    "sync"
)

// Task 任务类型,使用空接口表示任意类型的任务
type Task interface{}

// TaskHandler 任务处理函数类型
type TaskHandler func(Task)

// TaskDispatcher 任务调度器
type TaskDispatcher struct {
    taskQueue   chan Task
    handlers    map[interface{}]TaskHandler
    mutex       sync.RWMutex
    wg          sync.WaitGroup
}

// NewTaskDispatcher 创建新的任务调度器
func NewTaskDispatcher(queueSize int) *TaskDispatcher {
    return &TaskDispatcher{
        taskQueue:   make(chan Task, queueSize),
        handlers:    make(map[interface{}]TaskHandler),
    }
}

// RegisterHandler 注册任务处理函数
func (td *TaskDispatcher) RegisterHandler(taskType interface{}, handler TaskHandler) {
    td.mutex.Lock()
    defer td.mutex.Unlock()
    td.handlers[taskType] = handler
}

// Dispatch 启动调度器
func (td *TaskDispatcher) Dispatch(numWorkers int) {
    for i := 0; i < numWorkers; i++ {
        td.wg.Add(1)
        go func() {
            defer td.wg.Done()
            for task := range td.taskQueue {
                td.mutex.RLock()
                handler, ok := td.handlers[fmt.Sprintf("%T", task)]
                td.mutex.RUnlock()
                if ok {
                    handler(task)
                } else {
                    fmt.Printf("No handler registered for task type %T\n", task)
                }
            }
        }()
    }
}

// Enqueue 向任务队列中添加任务
func (td *TaskDispatcher) Enqueue(task Task) {
    td.taskQueue <- task
}

// Shutdown 关闭任务调度器
func (td *TaskDispatcher) Shutdown() {
    close(td.taskQueue)
    td.wg.Wait()
}

使用示例

func main() {
    dispatcher := NewTaskDispatcher(100)

    // 注册任务处理函数
    dispatcher.RegisterHandler("stringTask", func(task Task) {
        fmt.Printf("Handling string task: %s\n", task.(string))
    })

    dispatcher.RegisterHandler(123, func(task Task) {
        fmt.Printf("Handling int task: %d\n", task.(int))
    })

    // 启动调度器
    dispatcher.Dispatch(5)

    // 添加任务
    dispatcher.Enqueue("Hello, world!")
    dispatcher.Enqueue(456)

    // 关闭调度器
    dispatcher.Shutdown()
}

以上代码实现了一个通用的任务调度和处理框架,通过空接口来处理不同类型的任务,并且具备并发安全和良好的扩展性。TaskDispatcher 结构体负责管理任务队列和任务处理器,RegisterHandler 方法用于注册任务处理器,Dispatch 方法启动多个工作线程来处理任务,Enqueue 方法用于将任务添加到队列中,Shutdown 方法用于关闭调度器并等待所有任务处理完成。