【发布时间】:2020-03-20 09:59:29
【问题描述】:
我目前在正确使用异步方法时遇到问题。我可能误会了什么...
在我当前的项目中,我有一些应该并行运行的异步方法,但它们没有。所以我创建了一个小示例项目来重现错误。
class Program
{
static void Main(string[] args)
{
TaskAwaiter taskAwaiter = SomeParallelWork().GetAwaiter();
taskAwaiter.GetResult();
}
private static async Task SomeParallelWork()
{
Console.WriteLine(DateTime.Now + ": Start Parallel Work");
Task<string> task1 = HeavyDBWork(6000);
Task<string> task2 = HeavyDBWork(3000);
Task<string> task3 = HeavyDBWork(5000);
Console.WriteLine(DateTime.Now + ": All Parallel Work started");
await Task.WhenAll(new Task<string>[] { task1, task2, task3 });
Console.WriteLine(DateTime.Now + ": All Parallel Work done");
}
private static async Task<string> HeavyDBWork(int timeToWork)
{
Console.WriteLine(DateTime.Now + ": Start with heavy db work load: " + timeToWork);
await Task.Delay(timeToWork);
Console.WriteLine(DateTime.Now + ": End of heavy db work load: " + timeToWork);
return "SomeReturnValue";
}
}
输出如我所料:
20.03.2020 10:50:28: Start Parallel Work
20.03.2020 10:50:28: Start with heavy db work load: 6000
20.03.2020 10:50:28: Start with heavy db work load: 3000
20.03.2020 10:50:28: Start with heavy db work load: 5000
20.03.2020 10:50:28: All Parallel Work started
20.03.2020 10:50:31: End of heavy db work load: 3000
20.03.2020 10:50:33: End of heavy db work load: 5000
20.03.2020 10:50:34: End of heavy db work load: 6000
20.03.2020 10:50:34: All Parallel Work done
首先生成所有任务,然后并行运行。 但这不是我在项目中所经历的......
所以我用一些更“真实”的工作扩展了我的示例:递归斐波那契算法
class Program
{
static void Main(string[] args)
{
TaskAwaiter taskAwaiter = SomeParallelWork().GetAwaiter();
taskAwaiter.GetResult();
}
private static async Task SomeParallelWork()
{
Console.WriteLine(DateTime.Now + ": Start Parallel Work");
Task<long> fibuTask = CPUWork(40);
Task<string> task1 = HeavyDBWork(6000);
Task<string> task2 = HeavyDBWork(3000);
Task<string> task3 = HeavyDBWork(5000);
Console.WriteLine(DateTime.Now + ": All Parallel Work started");
await Task.WhenAll(new Task<string>[] { task1, task2, task3 });
await Task.WhenAll(new Task<long>[] { fibuTask });
Console.WriteLine(DateTime.Now + ": All Parallel Work done");
}
private static async Task<string> HeavyDBWork(int timeToWork)
{
Console.WriteLine(DateTime.Now + ": Start with heavy db work load: " + timeToWork);
await Task.Delay(timeToWork);
Console.WriteLine(DateTime.Now + ": End of heavy db work load: " + timeToWork);
return "SomeReturnValue";
}
private static async Task<long> CPUWork(int i)
{
Console.WriteLine(DateTime.Now + ": Start Fibu of " + i);
long fibu = Fibu(i);
Console.WriteLine(DateTime.Now + ": End Fibu of " + i);
return await Task.FromResult<long>(fibu);
}
private static long Fibu(int i)
{
if(i==1||i==2)
{
return (long)1;
} else
{
return Fibu(i-2) + Fibu(i - 1);
}
}
}
输出:
20.03.2020 10:56:09: Start Parallel Work
20.03.2020 10:56:09: Start Fibu of 40
20.03.2020 10:56:10: End Fibu of 40
20.03.2020 10:56:10: Start with heavy db work load: 6000
20.03.2020 10:56:10: Start with heavy db work load: 3000
20.03.2020 10:56:10: Start with heavy db work load: 5000
20.03.2020 10:56:10: All Parallel Work started
20.03.2020 10:56:13: End of heavy db work load: 3000
20.03.2020 10:56:15: End of heavy db work load: 5000
20.03.2020 10:56:16: End of heavy db work load: 6000
20.03.2020 10:56:16: All Parallel Work done
现在 Fibunacci Sequence 任务不仅仅是首先创建的,它是在创建其他任务之前等待的方式。 我希望代码能够创建所有任务并并行运行它们。我做错了什么?
感谢您的回答!
答案:
感谢 Johnathan、Lasse 和 Theodor,我能够修复我的代码示例。
所以新示例异步执行三个斐波那契算法。
class Program
{
static void Main(string[] args)
{
TaskAwaiter taskAwaiter = SomeParallelWork().GetAwaiter();
taskAwaiter.GetResult();
}
private static async Task SomeParallelWork()
{
Console.WriteLine(DateTime.Now + ": Start Parallel Work");
Task<long> fibuTask1 = CPUWork(45);
Task<long> fibuTask2 = CPUWork(40);
Task<long> fibuTask3 = CPUWork(40);
Console.WriteLine(DateTime.Now + ": All Parallel Work started");
//await Task.WhenAll(new Task<string>[] { task1, task2, task3 });
await Task.WhenAll(new Task<long>[] { fibuTask1, fibuTask2, fibuTask3 });
Console.WriteLine(DateTime.Now + ": All Parallel Work done");
}
private static async Task<string> HeavyDBWork(int timeToWork)
{
Console.WriteLine(DateTime.Now + ": Start with heavy db work load: " + timeToWork);
await Task.Delay(timeToWork);
Console.WriteLine(DateTime.Now + ": End of heavy db work load: " + timeToWork);
return "SomeReturnValue";
}
private static async Task<long> CPUWork(int i)
{
Console.WriteLine(DateTime.Now + ": Start Fibu of " + i);
Func<long> fibuFunc = () => Fibu(i);
Task<long> fibuTask = Task.Run(fibuFunc);
long fibu = await fibuTask;
Console.WriteLine(DateTime.Now + ": End Fibu of " + i);
return fibu;
}
private static long Fibu(int i)
{
if(i==1||i==2)
{
return (long)1;
} else
{
return Fibu(i-2) + Fibu(i - 1);
}
}
}
输出:
20.03.2020 11:59:39: Start Parallel Work
20.03.2020 11:59:39: Start Fibu of 45
20.03.2020 11:59:39: Start Fibu of 40
20.03.2020 11:59:39: Start Fibu of 40
20.03.2020 11:59:39: All Parallel Work started
20.03.2020 11:59:41: End Fibu of 40
20.03.2020 11:59:41: End Fibu of 40
20.03.2020 11:59:53: End Fibu of 45
20.03.2020 11:59:53: All Parallel Work done
【问题讨论】:
-
添加
async关键字并不会神奇地将其变成后台任务或单独的线程,您仍然需要实际上执行一些异步操作。在您的情况下,整个方法及其调用的所有内容仍然是 100% 同步代码,因此它将在返回任务之前运行完成。您可以使用Task.Run(搜索 SO 以获取示例)创建将使用线程池运行的任务。 -
您可以通过将
return await Task.FromResult<long>(fibu)替换为return fibu来简化它。 -
你应该阅读关于异步/等待和状态机devblogs.microsoft.com/premier-developer/…
标签: c# asynchronous parallel-processing async-await