Async/await for long-running API methods with progress/cancelation

前端 未结 1 1891
-上瘾入骨i
-上瘾入骨i 2021-01-02 16:22

Edit I suppose the proper way of forcing await to invoke the worker asynchronously is with a Task.Run, like this:


await Task.Run(() => buil         


        
相关标签:
1条回答
  • 2021-01-02 17:12

    As noted on the top of that blog post, the information in that post is outdated. You should use the new IProgress<T> API provided in .NET 4.5.

    If you're using blocking I/O, then make your core method blocking:

    public void Build(string sInputFileName, CancellationToken cancel, IProgress<int> progress)
    {
      using (StreamReader reader = new StreamReader(sInputFileName))
      {
        int nLine = 0;
        int nTotalLines = CountLines(sInputFileName);
    
        while ((sLine = reader.ReadLine()) != null)
        {
          nLine++;
          // do something here...
          cancel.ThrowIfCancellationRequested();
          if (progress != null) progress.Report(nLine * 100 / nTotalLines);
        }
    
        return nLine;
      }
    }
    

    and then wrap it in Task.Run when you call it:

    private async void OnDoSomethingClick(object sender, RoutedEventArgs e)
    {
      OpenFileDialog dlg = new OpenFileDialog { Filter = "Text Files (*.txt)|*.txt" };
      if (dlg.ShowDialog() == false) return;
    
      // show the job progress UI...
    
      CancellationTokenSource cts = new CancellationTokenSource();
      DummyWorker worker = new DummyWorker();
      var progress = new Progress<int>((_, value) => { _progress.Value = value; });
      await Task.Run(() => builder.Build(dlg.FileName, cts.Token, progress);
    
      // hide the progress UI...
    }
    

    Alternatively, you could rewrite Build to use asynchronous APIs and then just call it directly from the event handler without wrapping it in Task.Run.

    0 讨论(0)
提交回复
热议问题