c# - 如何使用 Task.WhenAll 一次运行 2 个计算
问题描述
我正在尝试学习如何使用异步任务,并且我真的很努力只是为了让一个简单的示例正常工作。我在下面提供了我想要实现的非常简化的版本。
public void Calculate()
{
int a1 = 1;
int a2 = 2;
int b1 = 3;
int b2 = 4;
int c3 = 5;
int c4 = 6;
int c5 = 7;
int c6 = 8;
int c7 = 9;
// Do next 2 lines in parallel
int rank1 = Evaluate(a1, a2, c3, c4, c5, c6, c7);
int rank2 = Evaluate(b1, b2, c3, c4, c5, c6, c7);
// wait for above 2 lines and use values to get result
int result = EvaluateOutcome(rank1, rank2);
}
public static int Evaluate(int i1, int i2, int i3, int i4, int i5, int i6, int i7)
{
// do something complicated and return value - simulate here with random number
Random rand = new Random();
return rand.Next(0,10);
}
public static int EvaluateOutcome(int rank1, int rank2)
{
return rank1 * rank2;
}
在我的真实代码中计算rank1
和rank2
是一个漫长的过程,但计算是相互独立的。我想尝试同时运行这两个计算,希望能减少一半的处理时间。我需要在计算结果之前等待两个计算完成。
我想我应该能够做类似的事情:
private async Task Evaluate(int a1, int a2, int b1, int b2, int c3, int c4, int c5, int c6, int c7)
{
Task task1 = Evaluate(a1, a2, c3, c4, c5, c6, c7);
Task task2 = Evaluate(b1, b2, c3, c4, c5, c6, c7);
await Task.WhenAll(task1, task2);
}
但这不会编译,我不确定如何从 Task 获取结果并将它们放入 myrank1
和rank2
int 变量中。我认为这应该非常简单,但我找不到一个明确的例子。一些帮助将不胜感激。
解决方案
您可以使用该Task.Run
方法将每个计算卸载到一个ThreadPool
线程,并使用该Task.WaitAll
方法阻塞当前线程,直到两个计算完成:
Task<int> task1 = Task.Run(() => Evaluate(a1, a2, c3, c4, c5, c6, c7));
Task<int> task2 = Task.Run(() => Evaluate(b1, b2, c3, c4, c5, c6, c7));
Task.WaitAll(task1, task2);
int rank1 = task1.Result;
int rank2 = task2.Result;
更有效的替代方法是使用该Parallel.Invoke
方法。核心区别在于当前线程也将通过执行两种计算之一来参与工作。所以只会使用一个额外的线程(来自ThreadPool
):
int rank1 = default;
int rank2 = default;
var parallelOptions = new ParallelOptions()
{
MaxDegreeOfParallelism = Environment.ProcessorCount
};
Parallel.Invoke(parallelOptions,
() => rank1 = Evaluate(a1, a2, c3, c4, c5, c6, c7),
() => rank2 = Evaluate(b1, b2, c3, c4, c5, c6, c7)
);
的文档Parallel.Invoke
有点令人困惑,因为它声明它执行每个提供的操作,可能是并行的。不用担心。计算不会并行发生的唯一情况ThreadPool
是 饱和。在这种情况下,第一种方法 ( Task.Run
+ Task.WaitAll
) 也将无法并行化计算,同时对池的饱和贡献更大。如果您想ThreadPool
摆脱等式,您可以使用 传递一个自定义TaskScheduler
,ParallelOptions
它在每个任务的专用线程上执行任务,就像在这里找到的那样。或者使用TaskCreationOptions.LongRunning
旗帜。
推荐阅读
- r - 谷歌幻灯片,R,d3:插入交互式可视化
- c++ - SLEEP:(Sleep 或 usleep)没有在 Linux 中暂停我的线程中的所有内容,但在 Windows 中会暂停?为什么?
- python - 如何将 csv 行导出到单独的 .txt 文件中
- pytorch - 使用由另一个函数计算的权重计算卷积
- php - 是否可以从文件开头读取一定数量的数字后的一定数量的字符
- java - 正则表达式 - 在第一次匹配后获取第二个单词
- reactjs - 如何从组件内更新路由器
- html - 媒体查询最大宽度不能包容地工作
- reactjs - 当服务器请求挂起时,禁用下拉选择
- python - 使用 pyinstaller 创建 exe 时找不到名为“PyQt5”的模块