Can a Task have multiple awaiters?
我正在为 Windows 8 项目使用异步服务,并且该服务有一些异步调用,一次只能调用一次。
1 2 3 4 5 6 7 8 | public async Task CallThisOnlyOnce() { PropagateSomeEvents(); await SomeOtherMethod(); PropagateDifferentEvents(); } |
由于不能将异步调用封装在 lock 语句中,我想到了使用
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 | private Task _callThisOnlyOnce; public Task CallThisOnlyOnce() { if(_callThisOnlyOnce != null && _callThisOnlyOnce.IsCompleted) _callThisOnlyOnce = null; if(_callThisOnlyOnce == null) _callThisOnlyOnce = CallThisOnlyOnceAsync(); return _callThisOnlyOnce; } private async Task CallThisOnlyOnceAsync() { PropagateSomeEvents(); await SomeOtherMethod(); PropagateDifferentEvents(); } |
因此,您最终会得到调用
这是一种"有效"的方法吗?还是这种方法有一些缺点?
一个任务可以有多个等待者。但是,正如 Damien 指出的那样,您提出的代码存在严重的竞争条件。
如果您希望每次调用方法时都执行代码(但不是同时),请使用
您提出的解决方案尝试组合多个调用,如果代码尚未运行,则再次执行该代码。这更棘手,解决方案在很大程度上取决于您需要的确切语义。这是一个选项:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 | private AsyncLock mutex = new AsyncLock(); private Task executing; public async Task CallThisOnlyOnceAsync() { Task action = null; using (await mutex.LockAsync()) { if (executing == null) executing = DoCallThisOnlyOnceAsync(); action = executing; } await action; } private async Task DoCallThisOnlyOnceAsync() { PropagateSomeEvents(); await SomeOtherMethod(); PropagateDifferentEvents(); using (await mutex.LockAsync()) { executing = null; } } |
使用
附言我的 AsyncEx 库中有
如果可能涉及多个线程,此代码看起来非常"活泼"。
一个例子(我相信还有更多)。假设
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 | Thread 1 Thread 2 public Task CallThisOnlyOnce() { if(_callThisOnlyOnce != null && _callThisOnlyOnce.IsCompleted) _callThisOnlyOnce = null; if(_callThisOnlyOnce == null) public Task CallThisOnlyOnce() { if(_callThisOnlyOnce != null && _callThisOnlyOnce.IsCompleted) _callThisOnlyOnce = null; if(_callThisOnlyOnce == null) _callThisOnlyOnce = CallThisOnlyOnceAsync(); return _callThisOnlyOnce; } _callThisOnlyOnce = CallThisOnlyOnceAsync(); return _callThisOnlyOnce; } |
您现在有 2 个呼叫同时运行。
对于多个等待者,是的,您可以这样做。我确定我在某处看到过 MS 的示例代码,其中显示了优化,例如
但是,我未能找到此代码示例。