控制台程序调用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
相关产品推荐
相关产品推荐

