如何将时基轮询与可等待任务相结合



我已经实现了一个基于Timer的轮询工作器。例如,您可以考虑客户端的TryConnect -我称之为TryConnect,它最终将在一段时间内连接。它处理多个线程,如果连接是在进程中已经所有随后的TryConnect返回立即没有任何额外的行动。在内部,我只是创建一个计时器,并在间隔时间内尝试连接——如果连接失败,我再试一次。等等。

的缺点是它是"fire&forget"模式,现在我想把它与"async/await"模式结合起来,即调用:

client.TryConnect(); // returns immediately
// cannot tell if I am connected at this point

我想这样称呼它:

await client.TryConnect();
// I am connected for sure

我如何改变我的实现来支持"async/await"?我正在考虑创建空的Task(仅用于await),然后用FromResult完成它,但是此方法创建一个新任务,它不完成给定的实例。

为了记录,当前的实现看起来像这样(只是代码的草图):

public void TryConnect()
{
   if (this.timer!=null)
   {
     this.timer = new Timer(_ => tryConnect(),null,-1,-1);
     this.timer.Change(0,-1); 
   }
}
private void tryConnect()
{
   if (/*connection failed*/)
     this.timer.Change(interval,-1);
   else
     this.timer = null;
}

缺乏一个好的最小化、完整和可验证的代码示例,因此不可能提供任何具体的建议。根据你所写的,有可能你要找的是TaskCompletionSource。例如:

private TaskCompletionSource<bool> _tcs;
public async Task TryConnect()
{
   if (/* no connection exists */)
   {
     if (_tcs == null)
     {
       this.timer = new Timer(_ => tryConnect(),null,-1,-1);
       this.timer.Change(0,-1); 
       _tcs = new TaskCompletionSource<bool>();
     }
     await _tcs.Task;
   }
}
private void tryConnect()
{
   if (/*connection failed*/)
     this.timer.Change(interval,-1);
   else
   {
     _tcs.SetResult(true);
     _tcs = null;
     this.timer = null;
   }
}

指出:

  • 您的原始代码示例将重试连接逻辑,如果TryConnect()在连接后再次被调用。我希望您真正想要的是检查是否存在有效连接,因此我稍微修改了上面的代码以检查是否存在有效连接。如果你总是想尝试一个新的连接,你当然可以删除这部分,即使一个已经存在。
  • 代码在设置结果后立即将_tcs设置为null。请注意,任何等待或以其他方式存储_tcs对象的Task值的代码都将隐式引用当前的_tcs对象,因此在这里丢弃该字段的引用并不是问题。
  • 没有非通用的TaskCompletionSource。因此,对于只需要Task的场景,您可以使用泛型类型和占位符类型,如我在这里所做的boolobject或其他类型。我可以像调用SetResult(true)一样调用SetResult(false),在这个例子中这并不重要。重要的是完成了Task,而不是返回什么值。
  • 上面使用async关键字使TryConnect()成为异步方法。恕我直言,这样更容易读懂,但当然会在额外的Task中产生轻微的开销,以表示方法的操作。如果你愿意,你可以直接做同样的事情,而不需要async方法:
public Task TryConnect()
{
   if (/* no connection exists */)
   {
     if (_tcs == null)
     {
       this.timer = new Timer(_ => tryConnect(),null,-1,-1);
       this.timer.Change(0,-1); 
       _tcs = new TaskCompletionSource<bool>();
     }
     return _tcs.Task;
   }
   return Task.CompletedTask;
}

相关内容

  • 没有找到相关文章

最新更新