Skip to content

超时读取 Channel ​

难度:⭐⭐ 中等 ​

考点 ​

  • select 多路复用
  • time.After / time.NewTimer 超时控制
  • context.WithTimeout 的等价实现

题目描述 ​

实现几个与超时相关的 channel 工具函数:

函数1:ReadWithTimeout ​

从 channel 读取一个值,如果超时则返回错误。

函数2:ReadMultipleWithTimeout ​

从 channel 读取最多 n 个值,总超时限制。

函数3:FirstResult ​

并发执行多个函数,返回第一个完成的结果(其余丢弃)。

函数签名 ​

go
func ReadWithTimeout(ch <-chan int, timeout time.Duration) (int, error)
func ReadMultipleWithTimeout(ch <-chan int, n int, timeout time.Duration) []int
func FirstResult(fns ...func() int) int

提示 ​

  1. select + case <-time.After(timeout) 是经典超时模式
  2. ReadMultipleWithTimeout 用 for 循环 + select
  3. FirstResult 每个函数启动一个 goroutine,结果写入共享 channel

参考答案(Go) ​

点击展开参考答案
go
//go:build ignore

package answer

import (
	"errors"
	"time"
)

var ErrTimeout = errors.New("read timeout")

func ReadWithTimeout(ch <-chan int, timeout time.Duration) (int, error) {
	select {
	case v := <-ch:
		return v, nil
	case <-time.After(timeout):
		return 0, ErrTimeout
	}
}

func ReadMultipleWithTimeout(ch <-chan int, n int, timeout time.Duration) []int {
	if n <= 0 {
		return []int{}
	}
	result := make([]int, 0, n)
	timer := time.NewTimer(timeout)
	defer timer.Stop()

	for i := 0; i < n; i++ {
		select {
		case v := <-ch:
			result = append(result, v)
		case <-timer.C:
			return result
		}
	}
	return result
}

func FirstResult(fns ...func() int) int {
	ch := make(chan int, len(fns))
	for _, fn := range fns {
		go func(f func() int) {
			ch <- f()
		}(fn)
	}
	return <-ch
}

持续学习,持续构建。