【问题标题】:Reporting Progress from Tasks报告任务进度
【发布时间】:2018-01-17 21:52:35
【问题描述】:

在使用 Task 的 WhenAll() 或 WaitAll() 方法时,有没有办法知道单个 Task 的状态。
当我为每个完成的任务使用 await Task.WhenAll(tasks.ToArray()) 时,我想知道该任务已经完成。

【问题讨论】:

  • @BugFinder 这不完全是我在寻找,我想异步运行所有任务并等待所有任务完成,但同时,我还希望收到每个任务的通知已完成。
  • 如果您以 continue 启动每个任务,您会在完成时收到通知
  • 如果我使用 continue ,它将等到第一个任务完成,然后它会开始第二个任务,我不希望这种行为。
  • 阅读stackoverflow.com/questions/43929319/… 它有关于如何做你想要更清洁的建议.. continuewith 可以工作它只是混乱

标签: c# multithreading asynchronous async-await task


【解决方案1】:

要报告async 或并发进程的进度,请使用IProgress<T> 抽象。使用 Progress<T> 实现,您可以轻松捕获当前上下文并在 ui 上下文上运行进度更新/完成表达式,同时在后台进行工作:

public class WorkItem {
    public async Task DoWork(IProgress<bool> completionNotification) {
        await Task.Delay(TimeSpan.FromSeconds(2));
        //Work Done
        completionNotification.Report(true);
    }

    //Get, Set, Fire Property change etc
    public bool Completed {
        get; set;
    }
}

public class ViewModel {
    public async void ButtonClickHandler(object sender, EventArgs e) {
        var workitemTasks = WorkItems.Select(workItem =>
            workItem.DoWork(new Progress<bool>(done => workItem.Completed = done)))
            .ToList();
        await Task.WhenAll(workitemTasks);
    }

    //Get, Set, Fire Property change etc
    public IEnumerable<WorkItem> WorkItems {
        get; set;
    }
}

More Info

Reporting Progress From Async Tasks @StephenCleary

【讨论】:

    【解决方案2】:

    可能有更好的方法来做到这一点,但这里有一个原始类,它接受一组未启动的任务,并在每次某些任务完成执行时触发一个事件:

    public class TaskBatchRunner
    {
        private Task[] _tasks;
    
        public event EventHandler<Task> TaskCompleted;
    
        public TaskBatchRunner(Task[] tasks)
        {
            _tasks = tasks.Select(t =>
                new Task(() =>
                {
                    t.ContinueWith(OnTaskCompleted);
                    t.Start();
                })).ToArray();
        }
    
        public void Run()
        {
            foreach (var t in _tasks) t.Start();
            Task.WaitAll(_tasks);
        }
    
        private void OnTaskCompleted(Task completedTask)
        {
            TaskCompleted?.Invoke(this, completedTask);
        }
    }
    

    用法:

            var taskRunner = new TaskBatchRunner(tasks.ToArray());
            taskRunner.TaskCompleted += MyTaskCompleted;
            taskRunner.Run();
            ...
    
        private void MyTaskCompleted(object sender, Task e)
        {
            System.Diagnostics.Debug.WriteLine($"task {e.Id} completed!");
        }
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2021-05-20
      • 2015-03-18
      • 2013-11-28
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多