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

控制台程序调用Observable的LastAsync()出现死锁如何解决?

死锁原因

你调用Replay(1)后返回的是IConnectableObservable<T>类型,这类多播操作符需要显式调用Connect()方法才会真正订阅上游的Observable序列、执行你的API调用逻辑。你当前的代码没有触发连接操作,上游Defer包裹的Flurl请求永远不会执行,LastAsync()会一直等待序列发出值并结束,因此形成永久阻塞。

修复方案

修改代码满足3项需求的核心是使用AutoConnect(1),它会在检测到第一个订阅者时自动调用Connect()触发上游执行,结合Replay(1)的缓存能力刚好匹配所有需求:

public static class Program
{
    public static async Task Main(string[] args)
    {
        var obs = Observable.Defer(() =>
                "https://api.publicapis.org"
                    .AppendPathSegment("entries")
                    .GetJsonAsync()
                    .ToObservable())
            .Select(x => x.title)
            .Replay(1)
            .AutoConnect(1); // 新增该行,第一个订阅时自动连接上游

        // 第一次订阅,触发API调用
        var title = await obs.LastAsync();
        Console.WriteLine($"Title 1: {title}");

        // 第二次订阅,直接取缓存值,不会触发新的API调用
        var title2 = await obs.LastAsync();
        Console.WriteLine($"Title 2: {title2}");
    }
}

注:因为你的API请求对应的Observable只会发出一个值后立刻结束,这里用FirstAsync()和LastAsync()效果完全一致,可按需选择。

修改后完全匹配需求:

  • 控制台程序使用await等待结果,async Task类型的Main方法会自动等待异步操作完成,不会提前退出
  • API调用包裹在Defer中,且AutoConnect(1)仅在第一个订阅者出现时才触发连接,满足延迟到第一次订阅才执行请求的要求
  • Replay(1)会缓存序列的唯一返回值,后续所有订阅都会直接拿到缓存值,不会触发新的API请求

内容的提问来源于stack exchange,提问作者void.pointer

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.09.28 06:45:07