如何在没有忙等待的情况下等待直到收到回调/通知?

问题描述

我了解如何在库代码await等待网络请求或其他长时间运行的操作完成,但我如何才能await在我自己的长时间运行的操作上不用忙着等待


这是忙等待解决方案。我怎样才能让它成为事件驱动的?

public async Task<DataBlock> ClickSend() {
    // await until someone calls DataReceived()
    while (_Block == null) {
        await Task.Yield();
    }
    return _Block;
}

// Something external calls this function.
// Once called,ClickSend should complete with this data.
public void DataReceived(DataBlock data_block) {
    _Block = data_block;
}
DataBlock _Block = null;

(这个问题与 How do I await events in C#? 完全不同,后者询问如何等待事件处理程序,但与 Promise equivalent in C# 非常相似。)

解决方法

Generally in concurrency 一个“未来”是返回值的占位符,它有一个关联的“承诺”,它被履行以传递最终的返回值。

在 C# 中,它们有不同的名称:future 是 Task 和 the promise is a TaskCompletionSource

您可以创建一个承诺,等待它,然后在您收到回调时履行它:

TaskCompletionSource<DataBlock> _Promise = new TaskCompletionSource<DataBlock>();

public async Task<DataBlock> ClickSend() {
    DataBlock block = await _Promise.Task;
    return block;
}

public void DataReceived(DataBlock data_block) {
    _Promise.TrySetResult(data_block);
}

Here's an executable example