我玩弄与周围的异步服务为Windows 8项目,有此服务,这只能在一个时间一度被称为的一些异步调用。
public async Task CallThisOnlyOnce()
{
PropagateSomeEvents();
await SomeOtherMethod();
PropagateDifferentEvents();
}
因为你不能在封装锁声明一个异步调用,我想到了使用的AsyncLock
模式,但比我想我不妨试试这样的事情:
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();
}
所以你最终会与呼叫CallThisOnlyOnceAsync
只执行一次simultanously,以及多个awaiters迷上了同样的任务。
这是这样做还是有这种方法存在一些缺点的一个“有效”的方式?
一个任务可以有多个awaiters。 然而,正如达指出,有一个与你的推荐码严重的竞争条件。
如果你想要的代码每个方法被调用(但不能同时使用),然后使用时间执行AsyncLock
。 如果你想一次执行的代码,然后使用AsyncLazy
。
你提出的解决方案试图将多个呼叫合并,再次执行代码,如果它尚未运行。 这是更棘手,而且该解决方案在很大程度上取决于你所需要的确切语义。 这里有一个选项:
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;
}
}
它也可以用做这个Interlocked
,但代码变得丑陋。
PS我有AsyncLock
, AsyncLazy
和其他async
-ready原语在我AsyncEx库 。
这段代码看起来很“活泼”,如果多个线程可能与此有关。
一个例子(我敢肯定有更多)。 假设_callThisOnlyOnce
目前null
:
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个电话同时运行。
至于多awaiters,是的,你可以做到这一点。 我敢肯定,我见过的示例代码从MS某处表示在EG的结果的优化Task.FromResult(0)
被收纳在一个静态成员和返回功能,想要回零的任何时间。
我有,不过,一直在查找这个代码示例不成功。