一个任务可以有多个awaiters?(Can a Task have multiple awaite

2019-07-04 02:27发布

我玩弄与周围的异步服务为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迷上了同样的任务。

这是这样做还是有这种方法存在一些缺点的一个“有效”的方式?

Answer 1:

一个任务可以有多个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我有AsyncLockAsyncLazy和其他async -ready原语在我AsyncEx库 。



Answer 2:

这段代码看起来很“活泼”,如果多个线程可能与此有关。

一个例子(我敢肯定有更多)。 假设_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)被收纳在一个静态成员和返回功能,想要回零的任何时间。

我有,不过,一直在查找这个代码示例不成功。



文章来源: Can a Task have multiple awaiters?