You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在async异步编程中实现类似协程WaitUntil的条件等待功能?

实现方案

完全可以实现你需要的WaitUntil异步等待逻辑,只需要自行封装对应异步方法即可,以下是不同场景的实现参考:

1. 基础通用实现

这个版本不需要依赖第三方库,适用于所有C# async/await场景:

public static class TaskExtensions
{
    public static async Task WaitUntil(Func<bool> condition, int checkIntervalMs = 50, CancellationToken cancellationToken = default)
    {
        // 每次检测间隔默认50ms,可根据精度需求自行调整
        while (!condition())
        {
            // 检测取消信号,避免死等待
            cancellationToken.ThrowIfCancellationRequested();
            // 等待指定间隔后再下一次检测,不阻塞当前线程
            await Task.Delay(checkIntervalMs, cancellationToken);
        }
    }
}

调用方式和你期望的完全一致:

// 基础调用,等待直到条件满足
await TaskExtensions.WaitUntil(() => conditionIsMet);

// 自定义检测间隔+传入取消令牌的进阶调用
await TaskExtensions.WaitUntil(() => conditionIsMet, 10, cancellationToken);

如果你想实现和你写的完全一样的Task.WaitUntil调用形式,可以给Task类加静态扩展(C# 7.0及以上版本支持静态扩展方法),或者直接自定义partial的Task类添加对应静态方法。

2. 高响应度低延迟实现

如果你对等待的响应速度要求很高,不想因为固定检测间隔产生延迟,可以用SpinWait替代Task.Delay,适合条件会很快满足的场景:

public static async Task WaitUntil(Func<bool> condition, CancellationToken cancellationToken = default)
{
    var spinWait = new SpinWait();
    while (!condition())
    {
        cancellationToken.ThrowIfCancellationRequested();
        // 先自旋几次,再让出线程时间片
        spinWait.SpinOnce();
        // 自旋次数到阈值后用Task.Yield避免占用过多CPU
        if (spinWait.NextSpinWillYield)
        {
            await Task.Yield();
        }
    }
}

注意事项

  • 建议传入CancellationToken,避免条件永远不满足时出现死等待问题
  • 如果条件是UI相关的状态检测,要保证条件委托的执行线程是UI线程,避免出现线程安全问题
  • 固定间隔版本CPU占用更低,适合等待时间较长的场景;自旋版本响应更快,适合等待时间很短的高实时性场景

内容的提问来源于stack exchange,提问作者Noob001

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.10.03 14:15:01