简体   繁体   English

具有异步/等待,RX和LINQ的异步消息处理

[英]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.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM