循环等待两件事?

awaiting two things in a loop?

如何同时等待两个或更多的东西(不同类型)?就像在事件循环中一样:

while(true) {
    Letter msg1 = await WaitForLetter();
    //read msg1 and reply.
    SMS msg2 = await WaitForSMS();
    //read msg2 and reply
}

这看起来不对。两条消息最终会互相阻塞吗?

目前,您的代码将依次等待每个方法完成。如果你想发送每条消息然后在最后等待两者,你可以使用 Task.WaitAll 方法(假设你的方法 return 一个 Task<T> 对象。

while(true) {
    Task<Letter> msgTask1 = WaitForLetter();
    Task<SMS> msgTask2 = WaitForSMS();

    Task.WaitAll(msgTask1, msgTask2);
}

然后您可以使用 Result 属性 获得每个任务的结果(再次假设您的方法 return Task<T>:

Letter msg1 = msgTask1.Result;
SMS msg2 = msgTask2.Result;

当然,这一切都假设WaitForLetterWaitForSMS的实现是独立的,不会互相阻塞。

如果您只想等待 任何 个任务完成,您可以使用 `Task.WaitAny' 来达到相同的目的。此 return 是已完成任务的索引,因此您知道哪一个已完成。

while(true) {
    Task<Letter> msgTask1 = WaitForLetter();
    Task<SMS> msgTask2 = WaitForSMS();

    var finishedTask = Task.WaitAny(msgTask1, msgTask2);
}

我认为您最好的选择是使用 Microsoft 的 Reactive Framework (NuGet "Rx-Main")。它与 Tasks 配合得很好。

这是您需要的代码:

var subscription1 =
    Observable
        .FromAsync(WaitForLetter)
        .Repeat()
        .Subscribe(msg1 =>
        {
            //read msg1 and reply.
        });

var subscription2 =
    Observable
        .FromAsync(WaitForSMS)
        .Repeat()
        .Subscribe(msg2 =>
        {
            //read msg2 and reply
        });

两者 运行 彼此独立并且 运行 异步。

要阻止他们运行宁只需这样做:

subscription1.Dispose();
subscription2.Dispose();

如果你真的想让它们运行像一个事件循环,消息都进入同一个线程,相互穿插,那么你可以这样做:

var eventLoopScheduler = new EventLoopScheduler();

var subscription1 =
    Observable
        .FromAsync(WaitForLetter)
        .Repeat()
        .ObserveOn(eventLoopScheduler)
        .Subscribe(msg1 =>
        {
            //read msg1 and reply.
        });

var subscription2 =
    Observable
        .FromAsync(WaitForSMS)
        .Repeat()
        .ObserveOn(eventLoopScheduler)
        .Subscribe(msg2 =>
        {
            //read msg2 and reply
        });

你还有一点 clean-up,但这可以很好地处理:

var subscriptions = new CompositeDisposable(
    subscription1,
    subscription2,
    eventLoopScheduler);

//then later

subscriptions.Dispose();