方法循环的异步编程
Asynchonous programming for method loops
我正在尝试学习异步编程以及如何从中受益。
我希望每当我循环执行需要很长时间才能完成的方法时,我都可以使用它来提高性能,例如以下方法。
string AddStrings()
{
string result = "";
for (int i = 0; i < 10000; i++)
{
result += "hi";
}
return result;
}
显然这个方法没有太大的价值,我特意弄低了效率,为了测试异步编程的好处。测试是通过循环方法 100 次来完成的,首先是同步的,然后是异步的。
Stopwatch watch = new Stopwatch();
watch.Start();
List<string> results = WorkSync();
//List<string> results = await WorkAsyncParallel();
watch.Stop();
Console.WriteLine(watch.ElapsedMilliseconds);
List<string> WorkSync()
{
var stringList = new List<string>();
for (int i = 0; i < 100; i++)
{
stringList.Add(AddStrings());
}
return stringList;
}
async Task<List<string>> WorkAsyncParallel()
{
var taskList = new List<Task<string>>();
for (int i = 0; i < 100; i++)
{
taskList.Add(Task.Run(() => AddStrings()));
}
var results = (await Task.WhenAll(taskList)).ToList();
return results;
}
超级乐观(天真),我希望异步循环的速度是同步循环的 100 倍,因为所有任务都是同时 运行。虽然事实并非如此,但循环时间减少了三分之二以上,从大约 5000 毫秒减少到 1500 毫秒!
现在我的问题是:
- 是什么让异步循环比同步循环快,但不是快将近 100 倍?我猜这 100 个任务中的每一个都在争夺有限的 CPU?
- 这是提高循环方法性能的有效方法吗?
提前致谢。
My hope is that I can use it to improve performance
不是真的。并发(并行或异步)可以 提高性能,但异步代码本身更多的是释放线程。异步代码有两个主要好处:
- Server-side 应用程序获得更好的可扩展性。通过使用 更少的 线程,异步代码可以比同步代码扩展得更远、速度更快。
- UI 应用获得更好的响应能力。通过释放 UI 线程,异步代码提供了更好的用户体验。
这些都与性能无关。例如,将同步 server-side 请求处理程序与其基本的异步对应项进行比较时,异步请求处理程序通常 较慢 (略微),但服务器作为一个整体可扩展性更好。
也就是说,异步代码可以实现自然并发(例如,Task.WhenAll
)。如果您最终确实添加了并发性,那么您 可以 看到一些性能优势 - 有时是非常显着的。
The test is done by looping over the method 100 times, first synchronously and then asynchronously.
从技术上讲,您在此处比较 single-threaded 和并行代码。
正如 Jeroen 在评论中指出的那样,如果您遇到并行问题,Parallel
或 PLINQ 是合适的工具。虽然您 可以 使用 Task.Run
,但它是一个非常 low-level 的并行编程工具。 Task.Run
更常用于“将一个东西推到线程池”,而不是“将这些100东西推到线程游泳池”。
What makes the asynchronous loop faster than the synchronous loop, but not nearly 100 times faster? I'm guessing each of the 100 tasks are fighthing for a limited amount of CPU?
是的。现在大多数机器都有 multi-core CPUs,每个核心一次只能做一件事。所以如果你有 4 或 8 个核心,那就是你的并行度的极限。
Is this a valid method to improve performance when looping methods?
如果你有很多工作要做并行,那么并行编程是可以接受的。同样,我建议使用 higher-level 构造,如 Parallel
或 PLINQ,它们具有更好的 built-in 分区策略和其他优化,这比在线程池中扔一堆任务更有效。
并行编程确实有其注意事项:
- 如果您的工作量太大 fine-grained,那么并行工作最终可能会 变慢 ,因为分区、排队和调度的开销抵消了并发带来的好处.
- 您通常希望在某些情况下避免并行,例如在服务器端处理请求。允许一个请求消耗整个服务器的所有 CPU 资源通常不是一个好主意。
现在,如果您想测试 异步 的好处,那么我建议使用本质上异步的操作(例如,客户端 Web 请求)。比如说,如果您的代码访问了 100 个 URL。那将是不需要线程池线程的更自然的异步。
我正在尝试学习异步编程以及如何从中受益。
我希望每当我循环执行需要很长时间才能完成的方法时,我都可以使用它来提高性能,例如以下方法。
string AddStrings()
{
string result = "";
for (int i = 0; i < 10000; i++)
{
result += "hi";
}
return result;
}
显然这个方法没有太大的价值,我特意弄低了效率,为了测试异步编程的好处。测试是通过循环方法 100 次来完成的,首先是同步的,然后是异步的。
Stopwatch watch = new Stopwatch();
watch.Start();
List<string> results = WorkSync();
//List<string> results = await WorkAsyncParallel();
watch.Stop();
Console.WriteLine(watch.ElapsedMilliseconds);
List<string> WorkSync()
{
var stringList = new List<string>();
for (int i = 0; i < 100; i++)
{
stringList.Add(AddStrings());
}
return stringList;
}
async Task<List<string>> WorkAsyncParallel()
{
var taskList = new List<Task<string>>();
for (int i = 0; i < 100; i++)
{
taskList.Add(Task.Run(() => AddStrings()));
}
var results = (await Task.WhenAll(taskList)).ToList();
return results;
}
超级乐观(天真),我希望异步循环的速度是同步循环的 100 倍,因为所有任务都是同时 运行。虽然事实并非如此,但循环时间减少了三分之二以上,从大约 5000 毫秒减少到 1500 毫秒!
现在我的问题是:
- 是什么让异步循环比同步循环快,但不是快将近 100 倍?我猜这 100 个任务中的每一个都在争夺有限的 CPU?
- 这是提高循环方法性能的有效方法吗?
提前致谢。
My hope is that I can use it to improve performance
不是真的。并发(并行或异步)可以 提高性能,但异步代码本身更多的是释放线程。异步代码有两个主要好处:
- Server-side 应用程序获得更好的可扩展性。通过使用 更少的 线程,异步代码可以比同步代码扩展得更远、速度更快。
- UI 应用获得更好的响应能力。通过释放 UI 线程,异步代码提供了更好的用户体验。
这些都与性能无关。例如,将同步 server-side 请求处理程序与其基本的异步对应项进行比较时,异步请求处理程序通常 较慢 (略微),但服务器作为一个整体可扩展性更好。
也就是说,异步代码可以实现自然并发(例如,Task.WhenAll
)。如果您最终确实添加了并发性,那么您 可以 看到一些性能优势 - 有时是非常显着的。
The test is done by looping over the method 100 times, first synchronously and then asynchronously.
从技术上讲,您在此处比较 single-threaded 和并行代码。
正如 Jeroen 在评论中指出的那样,如果您遇到并行问题,Parallel
或 PLINQ 是合适的工具。虽然您 可以 使用 Task.Run
,但它是一个非常 low-level 的并行编程工具。 Task.Run
更常用于“将一个东西推到线程池”,而不是“将这些100东西推到线程游泳池”。
What makes the asynchronous loop faster than the synchronous loop, but not nearly 100 times faster? I'm guessing each of the 100 tasks are fighthing for a limited amount of CPU?
是的。现在大多数机器都有 multi-core CPUs,每个核心一次只能做一件事。所以如果你有 4 或 8 个核心,那就是你的并行度的极限。
Is this a valid method to improve performance when looping methods?
如果你有很多工作要做并行,那么并行编程是可以接受的。同样,我建议使用 higher-level 构造,如 Parallel
或 PLINQ,它们具有更好的 built-in 分区策略和其他优化,这比在线程池中扔一堆任务更有效。
并行编程确实有其注意事项:
- 如果您的工作量太大 fine-grained,那么并行工作最终可能会 变慢 ,因为分区、排队和调度的开销抵消了并发带来的好处.
- 您通常希望在某些情况下避免并行,例如在服务器端处理请求。允许一个请求消耗整个服务器的所有 CPU 资源通常不是一个好主意。
现在,如果您想测试 异步 的好处,那么我建议使用本质上异步的操作(例如,客户端 Web 请求)。比如说,如果您的代码访问了 100 个 URL。那将是不需要线程池线程的更自然的异步。