我想在循环中调用两种方法。 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;
}
答案 0 :(得分:5)
不要做任何这些事情;你将有可能在整个地方遇到僵局。另外,不要将内容移动到线程上,除非它受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.
}
请记住, await是对工作流程的排序操作。这意味着在此任务完成之前不要继续此工作流程;去寻找其他工作流程。
练习:如何编写代码来表示工作流程: