c# - 具有同步和异步调用者的同步方法中的 Thread.Sleep 或 Task.Delay

标签 c# multithreading asynchronous async-await thread-sleep

我有一个同步方法:

public void DoStuff() {  
    DoThings(); 
    GraphClient.SetExtendedProperty(user, propertyName, value);     // this method occasionally throws an exception
    DoOtherThings();
}

Call3rdPartyMethod 使用 Azure Ad Graph Client API 进行 REST API 调用如果我尝试在 Active Directory 上设置扩展属性的值但未找到该值,则会引发异常。这种情况通常发生在我想要设置值之前,将新用户添加到目录中,并且扩展属性功能尚未扩展用户架构(似乎需要几秒钟)。

我用自己的包装器替换了 SetExtendedProperty 调用,其中包含繁忙等待循环中的调用:

public void TrySetProperty(GraphObject user, string propertyName, string value)
{

   var exceptions = new List<Exception>();

   for (int retry = 0; retry < 5; retry++)
   {
      try
      { 
          if (retry > 0)
              Thread.Sleep(1000);
              GraphClient.SetExtendedProperty(user, propertyName, value);
      }
      catch (Exception ex)
      { 
          exceptions.Add(ex);
      }
   }

   throw new AggregateException(exceptions);
  }
}

问题是我希望能够从同步和异步方法调用 TrySetProperty:

public void DoStuff() {  
    DoThings(); 
    TrySetProperty(user, propertyName, value);
    DoOtherThings();
}

public Task DoOtherStuffAsync() {
    await DoAsyncThings();
    TrySetProperty(user, propertyName, value);
    await DoOtherAsyncThings();
}

我无法将 SetExtendedProperty 更改为异步,并且我担心如果我从异步方法调用它,我不应该使用 Thread.Sleep - 而不是 Task.Delay()。谁能给点建议吗?

最佳答案

我推荐:

  • 如果可能的话,制作一个完全异步的版本。 REST API 本质上是异步的,但某些客户端库仍然过时(即只有同步方法)。
  • 如果可能,仅公开异步版本(因为操作本质上是异步的)。如果您必须支持同步 API(例如,为了向后兼容),则使用 boolean argument hack in my article on brownfield async .
  • 使用Polly用于重试逻辑。

假设您有一个完全异步版本的 GraphClient.SetExtendedProperty 正在运行,那么您的代码可能如下所示:

private static readonly Policy syncPolicy = Policy.Handle<Exception>().WaitAndRetry(5, _ => TimeSpan.FromSeconds(1));
private static readonly Policy asyncPolicy = Policy.Handle<Exception>().WaitAndRetryAsync(5, _ => TimeSpan.FromSeconds(1));

private static async Task TrySetProperty(GraphObject user, string propertyName, string value, bool sync)
{
    if (sync)
        syncPolicy.Execute(() => GraphClient.SetExtendedProperty(user, propertyName, value));
    else
        await asyncPolicy.ExecuteAsync(() => GraphClient.SetExtendedPropertyAsync(user, propertyName, value));
}

public static Task TrySetPropertyAsync(GraphObject user, string propertyName, string value) =>
    TrySetProperty(user, propertyName, value, sync: false);
public static void TrySetProperty(GraphObject user, string propertyName, string value) =>
    TrySetProperty(user, propertyName, value, sync: true).GetAwaiter().GetResult();

如果您的 TrySetProperty 逻辑确实如此简单(即,它实际上只调用 GraphClient 上的单个方法),那么您可以取消 bool 参数 hack更简单的代码:

private static readonly Policy syncPolicy = Policy.Handle<Exception>().WaitAndRetry(5, _ => TimeSpan.FromSeconds(1));
private static readonly Policy asyncPolicy = Policy.Handle<Exception>().WaitAndRetryAsync(5, _ => TimeSpan.FromSeconds(1));

public static async Task TrySetPropertyAsync(GraphObject user, string propertyName, string value)
{
  await asyncPolicy.ExecuteAsync(() => GraphClient.SetExtendedPropertyAsync(user, propertyName, value));
}

public static void TrySetProperty(GraphObject user, string propertyName, string value)
{
  syncPolicy.Execute(() => GraphClient.SetExtendedProperty(user, propertyName, value));
}

关于c# - 具有同步和异步调用者的同步方法中的 Thread.Sleep 或 Task.Delay,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/42203599/

相关文章:

ios - 多个 MIC 的 Rest Kit 持久性/性能问题

c# - MVC3 全局化 : need global filter before model binding

c# - 如何更改已从 C# 代码过期的 sql server 密码?

c# - 在整个 C# 解决方案中应用 Visual Studio 快速操作和重构

Javascript::是否可以创建一个新的音频对象数组?

javascript - 异步调用内的同步调用

javascript - Promise在这种情况下如何实现?

c# - 为什么*不* ReSharper 告诉我 “implicitly captured closure” ?

java - 有多少个 Java 垃圾收集器对象?

java - 为什么自定义阻塞队列在 Java 中不是线程安全的