C# 获取第一个IObservable事件,而不阻塞需要它的线程/任务
我正在考虑使用C# 获取第一个IObservable事件,而不阻塞需要它的线程/任务,c#,multithreading,reactive,C#,Multithreading,Reactive,我正在考虑使用IObservable在c#async方法中的请求-响应环境中获得响应,并替换一些旧的基于回调的代码,但我发现如果将值(Subject.OnNext)推送到可观察的,但FirstAsync尚未等待,然后,FirstAsync永远不会收到该消息 没有第二个任务/线程加上同步,有没有一种简单的方法可以让它工作 public async Task<ResponseMessage> Send(RequestMessage message) { var id = Guid
IObservable
在c#async
方法中的请求-响应环境中获得响应,并替换一些旧的基于回调的代码,但我发现如果将值(Subject.OnNext
)推送到可观察的,但FirstAsync
尚未等待,然后,FirstAsync
永远不会收到该消息
没有第二个任务/线程加上同步,有没有一种简单的方法可以让它工作
public async Task<ResponseMessage> Send(RequestMessage message)
{
var id = Guid.NewGuid();
var ret = Inbound.FirstAsync((x) => x.id == id).Timeout(timeout); // Never even gets invoked if response is too fast
await DoSendMessage(id, message);
return await ret; // Will sometimes miss the event/message
}
// somewhere else reading the socket in a loop
// may or may not be the thread calling Send
Inbound = subject.AsObservable();
while (cond)
{
...
subject.OnNext(message);
}
公共异步任务发送(请求消息)
{
var id=Guid.NewGuid();
var ret=Inbound.FirstAsync((x)=>x.id==id).Timeout(Timeout);//如果响应太快,甚至都不会被调用
等待DoSendMessage(id,消息);
return wait ret;//有时会错过事件/消息
}
//在其他地方读取循环中的套接字
//可能是也可能不是调用Send的线程
Inbound=subject.AsObservable();
while(cond)
{
...
subject.OnNext(消息);
}
我不能在发送请求之前简单地将
wait
用于FirstAsync
,因为这会阻止请求被发送。等待wait
将订阅可观察的。您可以通过调用ToTask,将订阅与Wait分开:
public async Task<ResponseMessage> Send(RequestMessage message)
{
var id = Guid.NewGuid();
var ret = Inbound.FirstAsync((x) => x.id == id).Timeout(timeout).ToTask();
await DoSendMessage(id, message);
return await ret;
}
公共异步任务发送(请求消息)
{
var id=Guid.NewGuid();
var ret=Inbound.FirstAsync((x)=>x.id==id).Timeout(Timeout.ToTask();
等待DoSendMessage(id,消息);
返回等待返回;
}
我仔细观察了一下,通过将热的可见光转换为冷的可见光,可以很容易地解决您的问题。将主题
替换为重放主题
。以下是文章:
解释如下:
Replay扩展方法允许您获取现有的可观测数据
按照ReplaySubject对其进行排序并给出“replay”语义。作为一个
提醒,ReplaySubject将缓存所有值,以便
订阅者还将获得所有值
使用TaskCompletionSource是一个选项?它看起来像什么?比如说,设置一个设置tcs结果的订阅,然后取消订阅本身。然后发送然后等待tcs?猜是这样吗?描述似乎并不能真正解释这一点。但是我要理解的是,
Where
,FirstAsync
等的链就像是“挂起”,而ToTask
,wait
,(或其他东西)使其处于活动状态并开始观察事件?是的。与其他LINQ构造一样,Rx使用其运算符建立一个“定义”,并且它仅在订阅时执行(在本例中,等待
观察,或转换为任务
)。