我应该在同步和异步方法的 C# 循环中执行'Task.Wait()'吗



我想在循环中调用两个方法。Step1() 必须在调用 Step2() 之前完成。但是在循环中,Step1() 可以在 Step2() 异步执行时启动。我是否应该简单地等待 Step2 任务,然后再允许执行任何其他"Step2"任务,就像我在下面的代码中所做的那样?

public MainViewModel()
{
StartCommand = new RelayCommand(Start);
}
public ICommand StartCommand { get; set; }
private async void Start()
{
await  Task.Factory.StartNew(() =>
{
Console.WriteLine($"{DateTime.Now:hh:mm:ss.fff} - Started processing.");
for (int i = 0; i < 10; i++)
{
_counter++;
string result = Step1(i);
_step2Task?.Wait();     //Is this OK to do???
Step2(result).ConfigureAwait(false);
}
_step2Task?.Wait();
Console.WriteLine($"{DateTime.Now:hh:mm:ss.fff} - Finished processing.");
});
}
private string Step1(int i)
{
Thread.Sleep(5000);   //simulates time-consuming task
Console.WriteLine($"{DateTime.Now:hh:mm:ss.fff} - Step 1 completed - Iteration {i}.");
return $"Step1Result{i}";
}
private async Task Step2(string result)
{
_step2Task = Task.Run(() =>
{
Thread.Sleep(4000);  //simulates time-consuming task
Console.WriteLine($"{DateTime.Now:hh:mm:ss.fff} - Step 2 completed. - {result}");
});
await _step2Task;
}

不要做任何这些事情;你会冒着到处死锁的风险。 另外,不要将内容移动到线程上,除非它是 CPU 密集型的。

重新开始:

  • 查找每个占用大量 CPU 资源的长时间运行的同步方法,并围绕它编写一个异步包装器。 异步包装器应获取工作线程,执行 CPU 密集型任务,并在执行完成后完成。现在,您始终在任务方面具有抽象,而不是线程

  • 将所有控制流逻辑移动到 UI 线程上。

  • 在任何地方放一个await,意思是"在等待的任务完成之前,在此之后的代码不得执行"。

如果我们这样做,你的代码就会变得简单得多:

// Return Task, not void
// Name async methods accordingly
private async Task StartAsync()
{
Console.WriteLine($"{DateTime.Now:hh:mm:ss.fff} - Started processing.");
Task task2 = null;
for (int i = 0; i < 10; i++)
{
// We cannot do Step2Async until Step1Async's task 
// completes, so await it.
string result = await Step1Async(i);
// We can't run a new Step2Async until the old one is done:
if (task2 != null) {
await task2;
task2 = null;
}
// Now run a new Step2Async:
task2 = Step2Async(result);
// But *do not await it*.  We don't care if a new Step1Async
// starts up before Step2Async is done.
}
// Finally, don't complete StartAsync until any pending Step2 is done.
if (task2 != null) {
await task2;
task2 = null;
}
Console.WriteLine($"{DateTime.Now:hh:mm:ss.fff} - Finished processing.");
}
private string Step1(int i)
{
// TODO: CPU intensive work here
}
private async Task<string> Step1Async(int i) {
// TODO: Run CPU-intensive Step1(i) on a worker thread
// return a Task<string> representing that work, that is
// completed when the work is done.
}
private void Step2(string result)
{
// TODO: CPU-intensive work here
}
private async Task Step2Async(string result) 
{
// TODO: Again, make a worker thread that runs Step2
// and signals the task when it is complete.
}

请记住,等待是工作流上的排序操作。 这意味着在此任务完成之前不要继续此工作流;去查找其他工作流

练习:您将如何编写代码来表示工作流:

步骤
  • 1 必须在步骤 2 之前完成
  • 任意数量的 Step2 可以同时运行
  • 在"开始"完成之前,必须完成所有步骤 2

最新更新