使用async/await在请求正在进行时,为多个函数调用返回相同的值

Rob*_*und 8 c# asynchronous

鉴于以下功能:

public async Task<int> GetValue() {
    var value = await GetValueFromServer();
    return value;
}
Run Code Online (Sandbox Code Playgroud)

我想完成这个.可以从程序的不同部分调用函数GetValue().当GetValueFromServer()正在运行时,我不想再发起一次调用.GetValueFromServer()运行时对GetValue()的所有调用都应返回相同的值,而不是启动另一个调用.在GetValueFromServer()未运行时调用GetValue()应该启动对GetValueFromServer()的新调用.

一个例子:

0.0: var a = await GetValue()
0.1: call to GetValueFromServer()
0.3: var b = await GetValue();
0.6: var c = await GetValue();
0.7: GetValueFromServer() returns 1 
0.9: var d = await GetValue();
1.0: call to GetValueFromServer()
1.3 GetValueFromServer() returns 2
Run Code Online (Sandbox Code Playgroud)

GetValue()在0.0,0.3和0.6的调用应该只触发对GetValueFromServer()的单次调用.所有三个呼叫者都应该收到相同的值.在0.9处调用GetValue()应该触发对GetValueFromServer()的另一个调用.

我仍然坚持使用Objective-C思考,我将使用块来实现这一目标.我会排队块,当对服务器的请求返回时,调用每个排队的块.

- (void)getValue:(void(^)(int value))block {
    [_runningBlocks addObject:[block copy]];
    if (_runningBlocks.count > 1) {
        return;
    }

    [self getValueFromServer:^(int value) {
        for (void(^)(int)b in _runningBlocks) {
           b(value);
        }
        [_runningBlocks removeAllObjects];
    ];
 }
Run Code Online (Sandbox Code Playgroud)

现在我想完成同样的事情,但使用async/await模式.这适用于Windows Phone 8.1(RT)应用程序,如果可能,我想避免使用第三方库/框架.

Sri*_*vel 8

您需要共享相同的任务才能返回相同的值(您需要共享状态).为此,您需要同步访问权限.

以下应该绰绰有余.

private object padLock = new object();
private Task<int> executingTask;
public async Task<int> GetValue() 
{  
    lock(padLock)
    {
        if (executingTask  == null || executingTask.IsCompleted)
            executingTask= GetValueFromServer();
    }

    var value = await executingTask;
    return value;
}
Run Code Online (Sandbox Code Playgroud)

  • @PatriceGahide .Net的锁定实现并不是非常昂贵(如果锁定仅仅是短暂的一段时间).它将在内部使用"SpinWait"或所谓的"Busy-Wait".如果需要一段时间,它将返回到内核对象.因此,没有上下文切换开销等.这比信号量版本更有效(我相信). (3认同)