System.Threading.Tasks.Extensions库简介

发布于:2025-06-28 ⋅ 阅读:(16) ⋅ 点赞:(0)

System.Threading.Tasks.Extensions 是一个重要的 .NET 库,它为 System.Threading.Tasks 命名空间提供了扩展功能,主要用于增强任务并行库(Task Parallel Library, TPL)的功能。

设计原理

1. 核心目标

  • 提供对 ValueTask 和 ValueTask<T> 的支持,减少异步操作中的堆分配

  • 扩展任务相关的API,提供更灵活的异步编程模式

  • 桥接同步和异步编程模型

2. 关键组件

  • ValueTask/ValueTask<T>:轻量级任务结构,避免在热路径中分配Task对象

  • TaskCompletionSource 扩展:支持更多任务控制场景

  • IValueTaskSource:允许自定义ValueTask行为

3. 性能考虑

  • 减少GC压力:通过值类型任务减少堆分配

  • 热路径优化:为高频调用的异步操作提供更高效实现

  • 同步完成优化:对于可以同步完成的操作避免状态机开销

主要用法

1. ValueTask 基础用法

public ValueTask<int> GetDataAsync()
{
    if (_cache.TryGetValue(key, out var data))
    {
        return new ValueTask<int>(data); // 同步完成
    }
    return new ValueTask<int>(LoadFromDatabaseAsync()); // 异步完成
}

2. 自定义 IValueTaskSource

public class CustomTaskSource : IValueTaskSource<int>
{
    public int GetResult(short token) => /* 结果 */;
    public ValueTaskSourceStatus GetStatus(short token) => /* 状态 */;
    public void OnCompleted(Action<object> continuation, object state, short token, ValueTaskSourceOnCompletedFlags flags) 
        => /* 完成回调 */;
}

public ValueTask<int> GetCustomDataAsync()
{
    var source = new CustomTaskSource();
    return new ValueTask<int>(source, token: 0);
}

3. 任务扩展方法

// 配置任务等待方式
await someTask.ConfigureAwait(false);

// 带超时的等待
await someTask.WaitAsync(TimeSpan.FromSeconds(5));

三个常见示例

示例1:高性能异步方法(减少分配)

public ValueTask<string> ReadFileAsync(string path)
{
    if (_memoryCache.TryGetValue(path, out string content))
    {
        return new ValueTask<string>(content); // 同步返回,无分配
    }
    return new ValueTask<string>(File.ReadAllTextAsync(path)); // 异步路径
}

应用场景:高频调用的缓存读取操作,大多数情况下可以从缓存同步返回。

示例2:自定义异步操作

public class TimerDelaySource : IValueTaskSource<bool>
{
    private readonly Timer _timer;
    private readonly CancellationToken _cancellationToken;
    private Action<object> _continuation;
    
    public TimerDelaySource(TimeSpan delay, CancellationToken cancellationToken)
    {
        _cancellationToken = cancellationToken;
        _timer = new Timer(_ => OnTimer(), null, delay, Timeout.InfiniteTimeSpan);
        cancellationToken.Register(() => OnTimer());
    }
    
    private void OnTimer()
    {
        var cont = Interlocked.Exchange(ref _continuation, null);
        cont?.Invoke(this);
    }
    
    public bool GetResult(short token) => !_cancellationToken.IsCancellationRequested;
    
    public ValueTaskSourceStatus GetStatus(short token) 
        => _continuation == null ? ValueTaskSourceStatus.Succeeded : ValueTaskSourceStatus.Pending;
    
    public void OnCompleted(Action<object> continuation, object state, short token, ValueTaskSourceOnCompletedFlags flags)
    {
        _continuation = continuation;
    }
}

public static ValueTask<bool> DelayAsync(TimeSpan delay, CancellationToken cancellationToken = default)
{
    return new ValueTask<bool>(new TimerDelaySource(delay, cancellationToken), 0);
}

应用场景:需要完全控制异步操作实现细节的高性能场景。

示例3:带超时的异步操作

public static async ValueTask<string> ReadWithTimeoutAsync(Stream stream, byte[] buffer, TimeSpan timeout)
{
    using var cts = new CancellationTokenSource(timeout);
    try
    {
        var readTask = stream.ReadAsync(buffer, 0, buffer.Length, cts.Token);
        return await readTask.ConfigureAwait(false);
    }
    catch (OperationCanceledException) when (cts.IsCancellationRequested)
    {
        throw new TimeoutException("读取操作超时");
    }
}

应用场景:网络请求或IO操作需要设置超时限制的情况。

最佳实践

  1. 优先使用ValueTask:当方法可能频繁同步完成时

  2. 避免多次await:ValueTask通常只能被await一次

  3. 注意对象池:对于自定义IValueTaskSource,考虑实现对象池

  4. 正确配置上下文:合理使用ConfigureAwait

性能考虑

  • 同步完成路径:ValueTask在同步完成时性能显著优于Task

  • 异步路径:两者性能相近,ValueTask稍慢(因结构体包装)

  • 内存占用:ValueTask减少GC压力,适合高频调用场景

这个库在现代.NET异步编程中扮演着重要角色,特别是在性能敏感的场景下,理解其设计原理和正确用法可以帮助开发者编写更高效的异步代码。