【问题标题】:Write an Async method that will await a bool编写一个等待 bool 的 Async 方法
【发布时间】:2013-02-13 21:36:21
【问题描述】:

我想编写一个方法,将 await 用于将变量设置为 true。

这是伪代码。

bool IsSomethingLoading = false
SomeData TheData;

public async Task<SomeData> GetTheData()
{
   await IsSomethingLoading == true;
   return TheData;
}

TheData 将由 Prism 事件与 IsSomethingLoading 变量一起设置。

我调用了GetTheData 方法,但我希望它异步运行(现在如果数据未准备好,它只会返回 null。(这会导致其他问题。)

有没有办法做到这一点?

【问题讨论】:

    标签: c# .net asynchronous async-await


    【解决方案1】:

    在很多情况下,您需要的是TaskCompletionSource

    您可能有一种方法能够在某个时间点生成数据,但它不使用任务来完成。也许有一种方法可以接受提供结果的回调,或者触发一个事件以指示有结果,或者只是使用您不倾向于重新考虑的ThreadThreadPool 进行编码使用Task.Run

    public Task<SomeData> GetTheData()
    {
        TaskCompletionSource<SomeData> tcs = new TaskCompletionSource<SomeData>();
        SomeObject worker = new SomeObject();
        worker.WorkCompleted += result => tcs.SetResult(result);
        worker.DoWork();
        return tcs.Task;
    }
    

    虽然您可能需要/想要将 TaskCompletionSource 提供给工作人员或其他一些类,或者以其他方式将其暴露给更广泛的范围,但我发现它通常不需要,即使它是一个非常适当时的强大选项。

    您也可以使用Task.FromAsync 基于异步操作创建任务,然后直接返回该任务,或者在您的代码中使用await

    【讨论】:

      【解决方案2】:

      您可以使用TaskCompletionSource 作为您的信号,而await 则:

      TaskCompletionSource<bool> IsSomethingLoading = new TaskCompletionSource<bool>();
      SomeData TheData;
      
      public async Task<SomeData> GetTheData()
      {
         await IsSomethingLoading.Task;
         return TheData;
      }
      

      在您的 Prism 活动中:

      IsSomethingLoading.SetResult(true);
      

      【讨论】:

        【解决方案3】:

        这对我有用:

        while (IsLoading) await Task.Delay(100);
        

        【讨论】:

          【解决方案4】:

          如果您不关心速度性能,我提出了一个非常简单的解决方案,但不是回答原始问题的最佳方法:

          ...
          public volatile bool IsSomethingLoading = false;
          ...
          public async Task<SomeData> GetTheData()
          {
              // Launch the task asynchronously without waiting the end
              _ = Task.Factory.StartNew(() =>
              {
                  // Get the data from elsewhere ...
              });
          
              // Wait the flag    
              await Task.Factory.StartNew(() =>
              {
                  while (IsSomethingLoading)
                  {
                      Thread.Sleep(100);
                  }
              });
          
             return TheData;
          }
          

          重要提示:@Theodor Zoulias 建议:IsSomethingLoading 应使用 volatile 关键字声明,以避免编译器优化和从其他线程访问时潜在的多线程问题。 有关编译器优化的更多信息,请参阅本文: The C# Memory Model in Theory and Practice

          我在下面添加一个完整的测试代码:

          XAML:

          <Label x:Name="label1" Content="Label" HorizontalAlignment="Left" Margin="111,93,0,0" VerticalAlignment="Top" Grid.ColumnSpan="2" Height="48" Width="312"/>
          

          测试代码:

          public partial class MainWindow : Window
          {
              // volatile keyword shall be used to avoid compiler optimizations
              // and potential multithread issues when accessing IsSomethingLoading
              // from other threads.
              private volatile bool IsSomethingLoading = false;
          
              public MainWindow()
              {
                  InitializeComponent();
          
                  _ = TestASyncTask();
              }
          
              private async Task<bool> TestASyncTask()
              {
                  IsSomethingLoading = true;
          
                  label1.Content = "Doing background task";
          
                  // Launch the task asynchronously without waiting the end
                  _ = Task.Factory.StartNew(() =>
                  {
                      Thread.Sleep(2000);
                      IsSomethingLoading = false;
                      Thread.Sleep(5000);
                      HostController.Host.Invoke(new Action(() => label1.Content = "Background task terminated"));
                  });
                  label1.Content = "Waiting IsSomethingLoading ...";
          
                  // Wait the flag    
                  await Task.Run(async () => { while (IsSomethingLoading) { await Task.Delay(100); }});
                  label1.Content = "Wait Finished";
          
                  return true;
              }
          
          }
          
          /// <summary>
          /// Main UI thread host controller dispatcher
          /// </summary>
          public static class HostController
          {
              /// <summary>
              /// Main Host
              /// </summary>
              private static Dispatcher _host;
              public static Dispatcher Host
              {
                  get
                  {
                      if (_host == null)
                      {
                          if (Application.Current != null)
                              _host = Application.Current.Dispatcher;
                          else
                              _host = Dispatcher.CurrentDispatcher;
                      }
          
                      return _host;
                  }
              }
          }
          

          【讨论】:

            猜你喜欢
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 2013-06-12
            • 1970-01-01
            • 1970-01-01
            相关资源
            最近更新 更多