面试题答案
一键面试- 设计资源清理方案
- 使用context.Context:
- 在Go中,
context.Context
是实现通知退出机制的核心。在启动每个需要管理资源的任务时,传入一个带有取消功能的context.Context
。例如,在开启数据库连接任务、文件操作任务、网络连接任务等时,将context.Context
作为参数传递进去。 -
ctx, cancel := context.WithCancel(context.Background()) go func(ctx context.Context) { // 数据库连接操作 db, err := sql.Open("mysql", "user:password@tcp(127.0.0.1:3306)/database") if err!= nil { log.Fatal(err) } defer db.Close() for { select { case <-ctx.Done(): return default: // 数据库操作逻辑 } } }(ctx)
- 在Go中,
- 利用defer语句:对于每个需要关闭的资源,使用
defer
语句来确保在函数返回时资源被正确关闭。如上述代码中对数据库连接db
使用defer db.Close()
。对于文件句柄,可以这样:-
file, err := os.Open("example.txt") if err!= nil { log.Fatal(err) } defer file.Close()
-
- 封装资源管理逻辑:将资源的初始化和关闭逻辑封装到独立的函数或结构体方法中。例如,将数据库连接和关闭操作封装到一个
Database
结构体的方法中:-
type Database struct { DB *sql.DB } func NewDatabase() (*Database, error) { db, err := sql.Open("mysql", "user:password@tcp(127.0.0.1:3306)/database") if err!= nil { return nil, err } return &Database{DB: db}, nil } func (d *Database) Close() { d.DB.Close() }
-
- 使用context.Context:
- 平衡资源清理复杂性和代码可维护性
- 简单业务场景:
- 特点:涉及的资源种类少,业务逻辑相对简单。
- 方案:直接使用
defer
语句配合context.Context
即可。例如,一个简单的网络客户端程序,只涉及网络连接资源。代码可以简洁地写成:ctx, cancel := context.WithCancel(context.Background()) conn, err := net.Dial("tcp", "127.0.0.1:8080") if err!= nil { log.Fatal(err) } defer conn.Close() go func(ctx context.Context) { for { select { case <-ctx.Done(): return default: // 网络读写操作 } } }(ctx)
- 优势:代码简单直接,可维护性高,资源清理逻辑一目了然。
- 复杂业务场景:
- 特点:涉及多种不同类型的资源,资源之间可能存在依赖关系,业务逻辑复杂。
- 方案:
- 采用分层和模块化设计。将不同类型资源的管理分别放在不同的模块中,如数据库资源管理模块、文件资源管理模块等。每个模块负责自己资源的初始化、使用和清理。
- 使用依赖注入来管理资源之间的依赖关系。例如,如果某个业务逻辑需要同时使用数据库连接和文件句柄,通过依赖注入将这两个资源传递进去,而不是在业务逻辑内部直接初始化资源。
- 可以使用一些设计模式,如享元模式来管理共享资源,减少资源创建和销毁的开销。例如,多个业务模块可能共享同一个数据库连接池,通过享元模式可以高效管理这个连接池。
- 优势:通过分层和模块化,使得代码结构清晰,便于维护。依赖注入和设计模式的使用可以有效地管理资源依赖和复杂性,提高代码的可扩展性和可维护性。
- 简单业务场景: