MST

星途 面试题库

面试题:Go语言函数签名与类型断言在并发场景下的优化使用

在一个并发的Go程序中,有多个`goroutine`向一个通道`chan interface{}`发送数据,数据类型可能为`struct { ID int; Data string }`或者`struct { Code string; Value float64 }`。编写一个函数`func concurrentHandler(ch chan interface{})`,在函数内部使用类型断言区分不同类型的数据,并对不同类型的数据进行不同的异步处理(例如:对第一种结构体类型的数据,将`ID`和`Data`拼接成字符串存入数据库;对第二种结构体类型的数据,将`Code`和`Value`进行某种数学计算并将结果写入文件)。要求处理过程尽可能高效,考虑并发安全和资源合理利用。最后返回处理结果的汇总信息。
17.3万 热度难度
编程语言Go

知识考点

AI 面试

面试题答案

一键面试
package main

import (
	"database/sql"
	"fmt"
	"io/ioutil"
	"sync"

	_ "github.com/lib/pq" // 假设使用PostgreSQL,根据实际情况替换
)

// 假设的数据库连接
var db *sql.DB

func init() {
	var err error
	// 初始化数据库连接
	db, err = sql.Open("postgres", "user=postgres dbname=mydb sslmode=disable")
	if err != nil {
		panic(err)
	}
}

type FirstStruct struct {
	ID   int
	Data string
}

type SecondStruct struct {
	Code  string
	Value float64
}

func concurrentHandler(ch chan interface{}) map[string]interface{} {
	var wg sync.WaitGroup
	result := make(map[string]interface{})
	firstResultChan := make(chan string)
	secondResultChan := make(chan float64)

	for data := range ch {
		switch v := data.(type) {
		case FirstStruct:
			wg.Add(1)
			go func() {
				defer wg.Done()
				// 拼接字符串并插入数据库
				insertStr := fmt.Sprintf("%d-%s", v.ID, v.Data)
				_, err := db.Exec("INSERT INTO some_table (col) VALUES ($1)", insertStr)
				if err != nil {
					fmt.Println("Database insert error:", err)
				}
				firstResultChan <- insertStr
			}()
		case SecondStruct:
			wg.Add(1)
			go func() {
				defer wg.Done()
				// 进行数学计算
				resultValue := v.Value * 2.0
				// 写入文件
				err := ioutil.WriteFile("result.txt", []byte(fmt.Sprintf("%s-%f", v.Code, resultValue)), 0644)
				if err != nil {
					fmt.Println("File write error:", err)
				}
				secondResultChan <- resultValue
			}()
		}
	}

	go func() {
		wg.Wait()
		close(firstResultChan)
		close(secondResultChan)
	}()

	firstResults := []string{}
	for res := range firstResultChan {
		firstResults = append(firstResults, res)
	}
	result["first_type_results"] = firstResults

	secondResults := []float64{}
	for res := range secondResultChan {
		secondResults = append(secondResults, res)
	}
	result["second_type_results"] = secondResults

	return result
}
  1. 数据库连接初始化:在init函数中初始化了一个数据库连接(这里假设是PostgreSQL,使用lib/pq驱动,实际可根据需求更换)。
  2. 结构体定义:定义了两种结构体FirstStructSecondStruct
  3. concurrentHandler函数
    • 使用switch v := data.(type)进行类型断言,区分不同类型的数据。
    • 对于FirstStruct类型的数据,启动一个goroutine拼接IDData,并插入数据库,同时将拼接结果发送到firstResultChan
    • 对于SecondStruct类型的数据,启动一个goroutine进行数学计算(这里简单乘以2.0),并将结果写入文件,同时将计算结果发送到secondResultChan
    • 使用WaitGroup等待所有goroutine完成后关闭结果通道。
    • 从结果通道中收集所有结果并汇总到result这个map中返回。

需要注意:

  • 实际应用中,要根据真实需求优化数据库操作,比如使用连接池、事务等。
  • 文件写入也可以考虑使用更高效的方式,如bufio
  • 以上代码只是示例,实际可能需要更多的错误处理和优化。