[英]Asynchronous message processing with async/await, RX and LINQ
I'm using Reactive Extensions in combination with async/await to simplify my socket protocol implementation. 我将Reactive Extensions与async / await结合使用以简化套接字协议的实现。 There's some actions that have to be performed when specific message arrives (eg send 'pong' to each 'ping' -message) and there's also some method's where we have to wait for some specific responses asynchronously.
当特定消息到达时(例如,向每个“ ping”消息发送“ pong”),必须执行一些操作,还有一些方法,我们必须异步地等待某些特定的响应。 The following example illustrates this:
以下示例说明了这一点:
private Subject<string> MessageReceived = new Subject<string>();
//this method gets called every time a message is received from socket
internal void OnReceiveMessage(string message)
{
MessageReceived.OnNext(message);
ProcessMessage(message);
}
public async Task<string> TestMethod()
{
var expectedMessage = MessageReceived.Where(x => x.EndsWith("D") && x.EndsWith("F")).FirstOrDefaultAsync();
await SendMessage("ABC");
//some code...
//if response we are waiting for comes before next row, we miss it
return await expectedMessage;
}
TestMethod() sends "ABC" to the socket and continues when for example "DEF" is received (there might be some other messages before that). TestMethod()将“ ABC”发送到套接字,并在收到例如“ DEF”(在此之前可能还有其他消息)时继续执行。
This works almost, but there's a race condition. 这几乎可以用,但是有比赛条件。 It seems that this code won't listen for messages until
return await expectedMessage;
似乎这段代码直到
return await expectedMessage;
才会侦听消息return await expectedMessage;
And this is a problem, since sometimes the message arrives before that. 这是一个问题,因为有时消息会在此之前到达。
FirstOrDefaultAsync
won't work here nicely: It doesn't subscribe until the await
line, which leaves you with a race condition (as you point out). FirstOrDefaultAsync
在这里不能很好地工作:在await
行之前,它不会订阅,这使您处于竞争状态(如您所指出的)。 Here's how you can replace it: 替换方法如下:
var expectedMessage = MessageReceived
.Where(x => x.EndsWith("D") && x.EndsWith("F"))
.Take(1)
.Replay(1)
.RefCount();
using (var dummySubscription = expectedMessage.Subscribe(i => {}))
{
await SendMessage("ABC");
//Some code... goes here.
return await expectedMessage;
}
.Replay(1)
makes sure that a new subscription gets the most recent entry, assuming one exists. .Replay(1)
确保新的订阅获得最新的条目(假定存在)。 It only works though if there's a subscriber listening, hence dummySubscription
. 它仅在有订户在侦听的情况下
dummySubscription
,因此是dummySubscription
。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.